Z-Index Is Weird (but positioning is much weirder)
If you’ve played around in CSS a bit, you got to the point where you wanted one thing to be on top of another thing. You found out about something called
z-index and read that this property changed the stack order. Elements with bigger numbers are on top of elements with smaller numbers.
Sounds good, so you added
z-index:2 to one of your things. That didn’t work so you tried
z-index:20 and eventually
z-index:999999. Nothing. So what does this thing do?
You’ve got the right idea, but you've got to learn positioning
Every HTML element has it’s own position value, which can be one of the following:
- static: this is the default value. A static element is position on the page wherever the page flow puts it. Static elements ignore other positioning declarations, z-index being one of them.
- relative: similar to
static, relative elements work with the flow of the page, but will take positioning declarations to disrupt its relative position. For example, give a relative element the rule of
top:100pxto make that element 100 pixels further from the top than it would be otherwise.
- absolute: This is a different concept entirely. An absolute element is removed from the page flow and is positioned according to its own rules.
- fixed: Similar to absolute, but fixed elements are direct children of the window. So if you have a fixed element with
bottom:10px; left:10pxit will always be in the bottom-left corner of your screen, wherever you scroll.
- sticky: A relatively new property that toggles between relative and fixed, depending on where you scroll. This is interesting, but a digression from what this post is about, so we'll ignore this one for now.
In the case of your fictional webpage problem you’re having, simply adding
position:relative to your element will make it work like you want, but let’s explore why that is.
Below, I have a CodePen for you to play with.
Here, you’ve got three boxes, each of them with their own specific rules, but by changing the
z-index values, you’ll be able to make considerable changes to how those elements are treated.
One more demo on how absolute positioning works
When you set an element to
position:absolute without any other rules attached it will try to position itself in the right area (but it probably won’t be in the right area). Once you start to give it positioning rules, it will position itself according to its nearest positioned parent.
That might sound confusing, so let’s look at this pen:
Here, I’ve got three paragraphs next to 3 boxes. Inside of each of those boxes is another box, these roles are basically the same, but the position attributes have been changed each time.
- The first box is a
relativebox with an
absolutebox inside it. This works how you’d hope and is a demonstration of what I’d like to happen here. The blue box flows with the content and properly contains its red child.
- The second box is a
fixedinside it, and this is lookin’ weird. The fixed box has broken outside the static box and scrolls with the page. Because we haven’t specified left or right attributes, the fixed box vertically matches up with its static parent
- The third box isn’t great either. The
absoluteparent is almost where it should be, but not lined up correctly because absolute positioning ignores padding. Also because it’s been removed from the layout, the absolute box is covering up the paragraph next to it. We could adjust that with
z-indexbut the elements would still collide with each other. The relative child is also screwed up. It wants to be the width of its container, but it's outside because the word takes up available space and
overflow:visiblemeans it can exist outside the box. Which is a whole other thing.
So, when you're trying to get all your elements sorted, think of
position, and the four directions (
left) as all part of the same group of rules.
Play with these variables together and if you find that you're spending your time tweaking variables because it still doesn't quite look right yet, that's also called What Writing CSS Is Like All The Time.