Skip to content
Optimal Lab

Frontend · interactive

Stacking contexts and z-index

The modal has z-index 9999 and the header only 10, yet the modal can end up underneath. z-index only competes inside the same stacking context, and some CSS properties quietly create a new one. This is the real browser rendering it.

.header { position: sticky; z-index: 10; }
.card { position: relative; z-index: 1; }
.modal { position: absolute; z-index: 9999; }
Header · z-index: 10
.card (stacking context, z 1)
Modal · z-index: 9999

Modal is trapped below the header

The card forms a stacking context. Everything inside it, the modal included, is painted as one layer at the card's level, which is below the header's 10. 9999 only beats siblings inside the card.

Card styles

Step 3 of 4

  1. 1

    Stacking contexts are nested layers

    Each context is painted as a unit. Children's z-index only orders things within their parent's context.

    Like layers inside a group in a design tool.

  2. 2

    More than z-index creates them

    Positioned + z-index, but also transform, opacity < 1, filter, will-change, isolation: isolate, and position: fixed/sticky.

    A harmless animation can start the bug.

  3. 3

    A high number can't escape

    Raising the modal to 999999 won't help. You'd have to raise the card, which drags everything inside along.

    Inspect with DevTools' Layers panel.

  4. 4

    Portal overlays to the top

    Render modals, menus and tooltips at the end of <body> (React's createPortal, or the native <dialog> top layer), and keep a small z-index scale.

    dialog.showModal()

In production

Tools and technologies

Overlays break the same way in every codebase.

Not tied to one language — use these names when you search docs or design a system.