Why z-index Doesn't Always Do What You Expect
Mention "painting order" or "stacking context" and most developers' eyes glaze over. But Martin Robinson at Igalia recently walked through a deceptively simple example that reveals exactly why z-index can behave counterintuitively—and the explanation lives deep in the CSS2 spec.
The setup is straightforward: two overlapping boxes, pulled together with negative margins. Add a third box as a child of the green one, then drop the green box's z-index to -1. Both the green and its yellow child stack beneath the blue box, which matches expectations.
<div class="blue box">1</div>
<div class="green box">2</div>

<div class="blue box">0</div>
<div class="green box" style="position: relative; z-index: -1;">-1
<div class="yellow box">-1</div>
</div>

A Massive z-index That Changes Nothing
Here's where things get confusing. Keep the green box at z-index: -1, but give the yellow child a z-index of 1,000. The visual result is identical—blue stays on top.
<div class="blue box">0</div>
<div class="green box" style="position: relative; z-index: -1;">-1
<div class="yellow box" style="position: relative; z-index: 1000;">1000</div>
</div>

It seems like the yellow box's enormous z-index should put it above everything, but it doesn't. The reason comes from CSS2's Appendix E, which defines how stacking contexts are painted.
We learn from the Appendix E that a stacking context is an atomically painted collection of page items. What does this mean? To put it simply, it means that things inside a stacking context are painted together, as a unit, and that items outside the stacking content will never be painted between them. Having an active
z-indexis one of the situations in CSS which triggers the creation of a stacking context. Is there a way we can adjust our example above so that the third element belongs to the same stacking context as the first two elements? The answer is that we must remove it from the stacking context created by the second element.
Because the yellow box is a child of the green box, both belong to the same stacking context, and that entire context is painted as a single unit. The blue box never gets painted "between" them—so no matter how high yellow's z-index goes, it's trapped inside its parent's context.
Escaping the Context
Getting yellow above blue requires pulling it out of green's stacking context entirely. Once that happens, yellow can compete on the same level as blue.

Robinson's full post digs further into how stacking order enables some real CSS tricks. It's a useful reminder that z-index is not a level playing field—stacking contexts change the game entirely, regardless of the values you throw at them.




