Lesson Description
The "z-index & Stacking Context" Lesson is part of the full, CSS Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:
Kevin explains z-index and stacking contexts, showing how elements layer based on z-index values. He demonstrates using position absolute and z-index, discusses common issues with stacking, and shows how isolation can create a new stacking context safely.
Transcript from the "z-index & Stacking Context" Lesson
[00:00:00]
>> Kevin Powell: So we started talking about z-index already. We saw it in action, but there's a really weird thing that can happen with z-index that brings in this topic of stacking contexts. Stacking contexts are, along with containing blocks, two parts of CSS that I like to call the either unknown or underappreciated fundamentals of CSS because they don't get enough talk. Containing blocks you rarely hear about.
[00:00:26]
You just get like, oh, you're going to make a position relative on the parent and it fixes it. You don't hear the term containing block, which should be talked about. Stacking context, you hear a bit more about them, but they still should be talked about more. So we already saw, I'm going to do a quick rundown again on it, but the very basics of z-index, which is dealing with stacking context, because it's the way things stack.
[00:00:49]
Box 1, box 2. Let's go on box 1. Position absolute. Comes out of the flow, the other stuff doesn't see it anymore, moves up underneath it. We can't even see that other box because it's the same size. Let's just do a left of 40 pixels and a top, oh, this is going to break things as well, 40 pixels. We should do bottoms. Oh, I already had a containing block set up. I thought of that ahead of time. I'm going to do bottom instead though, just so they're overlapping one another.
[00:01:25]
Not where I thought it would go. Oh, bottom and top. That's why. We'll stick with a left and switch that one over to a bottom. Perfect, just so they're overlapping and we can see both of them, and I'll move this one over a little bit more. I could do the same thing to my box too. Position absolute. Now the parent doesn't even see it, the whole height of the parent is collapsing away a little bit. We'll say, bottom 20 pixels now, left 50, 40 pixels, I don't know, something, so they're layered on top of each other.
[00:02:02]
And now I can come in with the z-indexes to layer them and move them around. So z-index 2, the box 1 goes on top, I come back on this one, they start fighting with each other. Who wants to go higher? This one gets a 10. It moves up on top. The simple principle of z-index seems really, really clear. The bigger the number, the higher up they go. Little bit different though down here, where everything is kind of broken, but I have three different colored boxes.
[00:02:32]
One thing I will say, I'm doing this with colored boxes because there's nothing else I could really do it with. Demos with only colors are really hard. I realize some people have vision issues with color. I did try and use a color palette that apparently works well across different types of color vision issues, but I apologize if there's any trouble. Hopefully we'll see it fixed when we get to the real world example after.
[00:02:59]
This yellow box is my box 3 here. Now my box 3 is inside my box too. So it makes sense that it's on top of everything, because I've moved my box to in front, so it's inside of there and it's coming out as well. Let's go in and have some fun with box 3. Position absolute and we'll say left 20 pixels, top 20 pixels, moving it down a bit. First of all, this top and left are not relative to the parent all the way out here.
[00:03:38]
This top and left are relative to box 2, because box 2 has a position other than static and box 3 is inside of box 2. So the parent, the direct parent there becomes the containing block for this one because of the way the nesting works and because they both have, or because the parent has positioning on it. Now where things get weird is what if I wanted this yellow box to go behind everything else?
[00:04:06]
Okay, no problem. We just learned that z-index -1 goes all the way back. It's not going anywhere. This is where stacking contexts come in. Stacking contexts are a pretty big pain point for a lot of people. The reason this isn't going anywhere with the negative 1, or even just really quickly, we do another thing here. Let's give this one a 2. We're going to give box 2 a 2. Trying to do math here. No, we're going to give this one a 3, 13, and we're going to, this one stays as a 2.
[00:04:49]
Even though this one is a 2, it's going on top of the one with the z-index of 3. So the negative 1 didn't push it all the way back, and having a bigger number here, and what people do when this happens is that 999 thing I talked about. The bigger the number, if it wasn't going ahead before, it's not going to go ahead now, right? There's obviously something else at play, so it's the stacking context that's come in.
[00:05:10]
If something has a position and a z-index on it, it is creating a new stacking context. It's a pain point and a very powerful feature if you understand how it works. The reason it's a pain point is this is confusing. What a stacking context means is this element is living within the stacking context of box 2. Then any number I give it here is only relative to that context that it's now inside of. So it can't escape outside of box 2, it lives inside of that realm.
[00:05:44]
We're resetting into a new form of stacking, we're not stacking with the rest of the document like we were earlier before. It's a really strange behavior, but again, once you sort of get used to it, it starts making a lot of sense, and we can take advantage of this. It's going to fix the problem that we were just talking about, but let's go and take a look at the project to highlight what's a more common issue.
[00:06:08]
I gave the div there that we didn't really need. I'm going to give this a class for now. We don't actually need this, just to highlight what can actually happen, we're going to call this like dark-bg or something like that. So my div of dark-bg, we come in here, just keep it with our core stuff so we can delete it after. Dark-bg. Background is going to be black. We'll give it some padding because we like padding on things that have backgrounds.
[00:06:39]
Doesn't really matter about the padding, but I've lost my images again. My images have a negative 1 z-index. That -1 is currently on the global stacking context scale, which just means go behind everything. This type of problem happens a lot. You have something, you've used a -1, and it's worked perfectly everywhere. You put it on some other place, there's a background color, you've lost your thing that had the -1 and you're very frustrated.
[00:07:03]
You've gone through this course though, now you go, oh wait, there's a thing called stacking contexts. I can create new ones. One way that we can create a stacking context, we just saw it. If a position, if an element has a position on it and a z-index on it, it creates a new stacking context. So my course already has a position of relative. The traditional fix for this is to then give this a z-index.
[00:07:35]
And as soon as I give that a z-index, I've created a new stacking context. The course is its own isolated context of stacking. This element that has a -1 is only -1 within this element and not within the greater picture of the entire website. So that means that it can't escape outside of there anymore. Yep, there was a question about the height of the container box. Does it calculate to zero when children are absolutely positioned?
[00:08:04]
It will go, yeah, so when we pull an element out of the flow using position absolute, as long as you don't actually have a height declared on it, which I've said we probably don't want to do, it's going to shrink down to as small as it can get. So in that demo I was looking at, we saw it got smaller, but there was still a title in there, so it didn't get to zero. If there's, if all of the direct children are, or yeah, if all the direct children are positioned absolute, then the height would go down to zero, yeah.
[00:08:31]
This is a, as I said, a part of CSS that can cause frustration, but when you know how it works, all of a sudden you can gain control and make sure problems aren't happening, where you're not having to go through and add a position to everything, because if not, I'd have to go, my image is a z-index 1, my next layer, like my text is a 2, the tag is a 3 or something, and you start having to add z-indexes to everything and it gets a little annoying.
[00:08:57]
So knowing that you can just make a new stacking context and contain it and then just you're only playing within that element, it makes life a lot easier. This was the traditional way of doing it, because it was the easiest way or it was the only way we could do it without any additional side effects. Position relative technically has a side effect on it because it is creating a containing block. In our case, we wanted that anyway, so it's completely fine if we wanted to do this.
[00:09:24]
Maybe having a z-index on here, then you have other things being layered, you're coming in, you're changing it, you never know, but I'll say it's not the end of the world. But I do want to let you know that we have a new property in CSS. It's not new, it's been around for a while, just nobody knows about it. It is newer, I guess, just as well. Isolation: isolate. That's the only value you'd ever put.
[00:09:50]
I forget even what the default is. The only thing this does is create a new stacking context and does nothing else. So if you don't need a position relative, you just need something to create a new stacking context, this is the simplest way to do it without having any side effects whatsoever. It's interestingly enough, not part of the positioning spec, it's part of the blending modes and other part of the spec, because we have these fancy things we can do with effects in CSS, and this potentially can help with issues that arise from that.
[00:10:24]
So it was added there, but I use it all the time to create new stacking contexts, so I'm able to use negative z-indexes without any issues. Sometimes you're going to run into issues with z-index that are unexpected because there's a lot of things that do create new stacking contexts, so there's a full list here of them on the MDN. It's just don't memorize them, just be aware that they exist. So we talked about it, positioned elements with a z-index, fixed and sticky automatically do.
[00:10:53]
We talked about container type before, size and inline size, those are creating new stacking contexts. Flex items and grid items with z-index, I didn't mention this, but you do not need positioning with flex or grid items if you do need to layer them. Opacity lower than one. We haven't talked about opacity, we will soon. Mix blend mode, that's where you're blending elements together, it's kind of weird.
[00:11:17]
And a whole bunch of other properties down here. There's our isolation isolate, and there's a few others as well. There's a long list of ways to accidentally create new stacking contexts. So if you ever run into an issue where you add something and your layout breaks a little bit, just be aware that you, this idea that maybe I accidentally created one, you really don't want to memorize the list because some of these seem kind of random.
[00:11:40]
It's all things that the browser has to do, especially like opacity transforms, these types of things that just with the algorithm, the way the browser's working, there's no way it would be able to function without doing it, which is why this is happening and it's side effects of using those properties. But the main thing is just be aware that you might accidentally create one, which potentially could cause some problems.
[00:12:05]
And we already did that, so we don't have to dive into it now. I have a question. So we use absolute positioning in this. Is there a benefit to using that over using grid for this kind of a layout? That's a good question. We could use grid for this and actually do it with like a, there's a way you do like a grid with a named area where they're all using the same area name and the elements all just stack on top of each other and then you can use that index to order them or just change the order they are in the HTML.
[00:12:35]
Works perfectly fine. I wouldn't say one's better than the other. The one advantage with positioning is just being able to do like an inset and setting it up so it fills up the entire space. The advantage with grid is the image would be part of the content, so it's potentially that's actually creating the size of your card, instead of having to muck around with padding and doing other things, so I'd say it depends on the situation that you're in.
[00:12:58]
Now, I'm going to do a quick fix here, just before we move into the next section to go back over a few of the things that we've looked at. Let's make this a little bit wider, just really quickly. My line heights are a little bit big. We have this giant space under here, here too, and this is just because they're grid items, they're stretching to match the row. The tallest rows are defining the heights.
[00:13:22]
So the simplest way for me, I think, to be able to do this is we can come in and actually just fix the line heights, and I do have headings or classes on all of these, so course title, the paragraph is a course description. So I'm going to come in, I'm going to say my course titles should maybe be a little bit smaller. Those are h3s, I think. And did I set a size on my h3? Let's just go look really fast if I did by default or not.
[00:13:47]
So I was saying there were 600. I think for now I'm actually going to come in. Oops, I should have stayed in my CSS file. And this is one of those things where you'll have a general style on your h3s. You want them all generally to look the same, and then you might run into a situation where actually this specific one should be smaller, so you just select it with a class to modify it. We get more specific in the areas we need to.
[00:14:16]
So far, maybe it's my font-size 500, just to shrink them down a little bit. Maybe this text could be smaller, maybe it's okay. The main thing I wanted to look at also is turning these courses into grid items so that I could align the content down at the bottom. You could also do this with flexbox, either one of them would work. There is a side effect to it though. So we're going to come on the course.
[00:14:41]
I said how I like organizing my CSS a little bit here. I do like having my display property at the top. Display of grid, and you might have noticed we have really big spacing now. So part of that is the way the auto rows are being created and they're stretching a little bit. It's like, okay, I want to line everything at the bottom. Cross axis is justification up and down as alignment, and I want all of, let's actually, let's use our inspector whenever we're not sure.
[00:15:11]
Inspector is your friend, without responsive mode on. This is a grid now, let's go see if we can find it. There's my grid, so we can see what's happening. And we can see that the rows are really big, but I also have margin on these elements that's causing them to be bigger. We talked about collapsing margins earlier. One side effect of both flexbox and grid is margins no longer collapse. And that's because the margins can't collapse because we're now inside of our cells.
[00:15:39]
Before they were, these elements were touching, now each element is within its own cell and the margin is pushing against the cells. So a lot of the time, if you have something that's a display grid that's just to like align and do simple layout, but you're not making an actual columns or doing other things like that, it's another very common case where we could just say, course, select all the direct children, margin of zero.
[00:16:02]
You might be leaning more and more to being like, oh, I get why Kevin said a lot of people do this right now, because we're running into lots of situations where margins are sort of getting in our way. I'm going to leave it like this for now. Get rid of those margins. Everything's a little bit too close together, but with grid, we have the better version than margins, which is our gap. Maybe something a little bit small, just add a bit of space between them.
[00:16:38]
We still have the alignment issue. We can see. Let's go grab that one. Where this grid. We can find it. Think it's that. There's this weird empty space that's showing up in my grid cells. This is one of the hardest things to debug in my own experience, just because there's no way of finding that. You're never going to find a margin, never going to find, there's nothing, there's nothing really causing that other than what we looked at where grids will stretch to match their own height, and the rows will grow.
[00:17:10]
You can go back over some of the older demos to see that when I added a height, the whole thing just grew and the rows were growing along with it. Hardest thing to debug because there's nothing defined for it, but it means we want the whole grid to get pushed down to the bottom. So most people, because I said you're going to use your align-items, we'll start with that, align-items of end. They've moved down to the bottom, but they've moved down to the bottom of their own cells, and the cells are still too big because it's the auto that's stretching to fill up the whole height.
[00:17:44]
So if this happens, it's the one time where we actually want to align content. Take that entire grid and push the entire thing down to the bottom. Now they're all as small as they can get and they're all lined up on the bottom of their parent. Just before you did that change, yep. Why did, why is box 5 appearing different than box 1? The colors of them? No, no, the spacing was different. Oh, okay, yeah, good question.
[00:18:10]
So the spacing, let's go back to that one. So this one doesn't have the extra spacing on it, and this one does. The reason that's happening, fantastic question, is because only one of these elements has extra lines of text in it, which is making that element taller, so that its siblings in the same row are matching the height of that one. So these ones actually looked fine, it was only in this situation where we were running into that little problem there.
[00:18:18]
Yeah, good catch. So it's an easy one to miss, but again, all of these things start coming back the more we start using them.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops