z-index
What a stacking context is
z-index is not a global ranking. It ranks an element against its siblings inside the nearest stacking context — a self-contained group that is flattened and then placed, as one unit, in its parent’s order. A child can never climb out of its group, however large its number. That is the whole reason z-index: 9999 loses.
With nothing on the parent, the child’s 9999 competes with the sibling’s 2 and wins. Any other option makes the parent a stacking context: the 9999 now only ranks the child inside the parent, and the parent as a whole sits below the sibling.
Use it for
- Reading a z-index bug: find the nearest ancestor of each element that forms a context, and compare those two ancestors, not the elements themselves.
- Predicting overlap between components that were written separately and know nothing about each other’s numbers.
Watch for
- Raising the number is never the fix when the two elements are in different contexts. The comparison is happening further up the tree.
- z-index only applies to positioned elements and to flex and grid items. On a static block in normal flow it is ignored.
- A context is created by many properties that have nothing to do with layering — which is why adding a fade-in animation can suddenly put a dropdown behind the next section.
.card { position: relative; z-index: 1; } /* a context: children rank inside it */
.card .menu { z-index: 9999; } /* 9999 within .card, never beyond */
.next-card { position: relative; z-index: 2; } /* paints over .card and its menu */