CSS z-index and stacking context.

Sam RuebyCSS Leave a Comment

It may be shocking to find out for beginners that don’t know, that CSS’s z-index property isn’t global. The z-index property is relative to the current stacking context. Put even more simply:

You can’t set an element’s z-index to a smaller number than another element’s z-index and have it appear under that other element, if your element has any ancestor with a z-index of a higher number than the other element.

What? That was still complicated. Let’s go to an example. Here is a very simple example of how people understand the z-index property at first:

Example demonstrating how z-index works

The numbers inside the square represents their z-index value

Each number inside of the div represents their z-index value. This is exactly how people picture it works: 5 is a higher number than 4 so 5 is on top of 4, 4 is a higher number than 3 so 4 is on top of 3 and so on. Easy.

But here’s an example of when things get more complicated:

3 squares where one looks like it would be on top of the others but isn't

In this example, 2 is a smaller z-index than 5, but is clearly on-top.

What’s interesting here is that the square with a z-index of 2 is on top of the square with the z-index of 5. But I thought that anything with a higher z-index than another would be on top? Nope. In this case, the blue square is a child of the red square. This creates a stacking context inside of the red square. No matter what, any child of the red square will not appear under it. This example can be found here.

That was a fun fact, but when will it really be helpful to know?

I ran into a situation where this fact caused some real confusion. It’s easy to see in the above example “oh, 2 is inside of the 5 so that’s why it’s on top”. It becomes way less clear when your metaphorical 2-square is a deep decedent of your 5 square. This can happen if you’re styling a complicated control, built by another company (like Telerik!) where you have little to no control over the resulting markup. Worse is when one of those child element is positioned far away from where it actually lands on the screen, it becomes very difficult to to see why this element all the way over here is being covered up.

One more thing.

If you’re setting z-index, please don’t set it to some crazy-high value. Especially since we are now aware of stacking context, setting your element to a value of 10000 isn’t buying you anything. Within the same stacking context, 2 is higher than 1 and will be on top.

The rules of stacking context are even more complicated. Learn more about them on MDN at https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context