z-index Only Works Inside Its Stacking Context
SHOULD: z-index is compared only within a stacking context, not globally. transform, opacity<1, filter, will-change, position:fixed/sticky, isolation, and flex/grid children with z-index all create one — trapping descendants no matter how high their z-index. Do not fix overlap with a bigger number; remove the accidental context or lift the overlay out of the trapping ancestor.
A parent with transform, opacity, or filter makes a new stacking context that traps its children's z-index — the fix is not a bigger number
/* z-index:9999 inside a transformed parent can't beat a later sibling. */
.card { transform: none; } /* or move the overlay to a portal / higher context */Bad
Good
Why it matters
The recurring bug: a dropdown set to `z-index: 9999` still renders under the next section and nobody can explain why the number does not win. z-index is not global — it is compared only among siblings inside the same STACKING CONTEXT, and a long list of ordinary CSS silently creates one: `transform`, `opacity` below 1, `filter`, `backdrop-filter`, `will-change`, `position: fixed`/`sticky`, `isolation: isolate`, and being a flex/grid child that has a z-index.
Once a parent forms a context, its descendants' z-index are resolved only against each other and the whole subtree is clamped to the parent's own place in the stack — so a `9999` inside a `transform`ed card can never climb above a sibling card that comes later in the DOM. Raising the number is the wrong fix and starts the arms race that layout-ibelick-z-index-scale exists to prevent.
The right fixes: remove the accidental context (drop the stray `transform`/`opacity`), or lift the overlay out of the trapping ancestor entirely — the same escape move layout-impeccable-clipped-overflow prescribes for a popover trapped in an `overflow` ancestor.