See exactly why z-index sometimes works — and exactly why it doesn't.
Drag the sliders to change each box's z-index. The box with the highest value floats on top.
All three boxes share the same stacking context — so z-index works as expected here.
position value other than static.
An element with position: static (the default) ignores z-index entirely — set it to
relative, absolute, fixed, or sticky first.
This is where most developers get stuck. When a parent creates its own stacking context, its children are trapped inside it — no matter how high their z-index is, they can never escape to appear above elements in a higher stacking context.
The red box has z-index: 9999 but sits
behind the cyan box with z-index: 2.
Why? Its parent has opacity: 0.9, creating a stacking context that traps it.
Remove opacity from the parent (or set it to exactly 1),
and the stacking context disappears. Now z-index: 9999 correctly floats above z-index: 2.
z-index: 9999 inside a context at z-index: 1
will always sit below a sibling context at z-index: 2 — no matter what.
The child's z-index only battles other children within the same context.
These CSS properties silently create a new stacking context on the element they're applied to. Once you know them, you'll never be surprised by a broken z-index again.
position + z-index ≠ autoThe original trigger. Any positioned element (relative, absolute, fixed, sticky) with a z-index value other than auto.
opacity < 1Setting opacity to anything below 1 (even 0.99) creates a stacking context. The most common hidden trap developers hit.
transform ≠ noneAny CSS transform — translateX(), scale(), rotate() — creates a stacking context, even translateZ(0) used as a GPU hack.
filter ≠ noneCSS filters like blur(), drop-shadow(), and brightness() all create stacking contexts.
backdrop-filterAdding a backdrop-filter (for glassmorphism effects) always creates a stacking context.
will-changeProperties like will-change: transform or will-change: opacity create a compositing layer and therefore a stacking context.
position: fixed or stickyBoth of these always create a stacking context, regardless of z-index value.
z-index ≠ autoA direct child of a flex or grid container creates a stacking context when given a non-auto z-index — no position needed.
The yellow box always has z-index: 999. Toggle properties on the blue parent to see when it gets trapped.