Debugging / advanced

Z-index triage: debug stacking contexts before raising numbers

If z-index is not working, the element is usually inside a stacking context that matters more than the number.

When an element refuses to appear above another element, raising z-index to 999999 is a guess. The real question is: which stacking context is it in?

A stacking context is a local layering system. Children can compete inside it, but they cannot escape it to beat elements in a higher outside context.

Step 1: Identify the positioned element

z-index applies to positioned elements and some layout contexts. Confirm the element actually participates in stacking.

.popover {
  position: absolute;
  z-index: 20;
}

If the element is not positioned and not in a context where z-index applies, the number may do nothing.

Step 2: Walk up the ancestors

Look for properties that create stacking contexts:

  • position with a z-index.
  • opacity less than 1.
  • transform, filter, or perspective.
  • isolation: isolate.
  • contain: paint.
  • Some container query and compositing scenarios.

The surprising offender is often a wrapper with transform: translateZ(0) or opacity: 0.999.

Step 3: Define a layer scale

:root {
  --layer-base: 0;
  --layer-dropdown: 20;
  --layer-sticky: 30;
  --layer-modal: 50;
  --layer-toast: 60;
}

A layer scale prevents arbitrary escalation. It also makes it clear when a component should not be able to beat a modal.

Step 4: Move the layer boundary if needed

Sometimes the fix is not a larger number. It is rendering the popover near the end of the document, removing an accidental stacking context, or adding isolation: isolate to contain a component that should not leak over the page.

Good layering is architecture. The number is only the last step.

References