Start a project

Tool 53 of 194 · CSS

Z-index & Stacking Context Debugger

Paste the HTML and CSS, and see each stacking context outlined, the real paint order, and a plain explanation of any z-index that loses, with the fix.

Z-index & Stacking Context Debugger at a glanceIllustration: 1, HTML and CSS; 2, processed in your browser; 3, Stacking contexts.Z-index & Stacking Context Debugger</>1HTML and CSS3Stacking contexts2In yourbrowser
1 HTML and CSS 2 processed on your device 3 Stacking contexts

Z-index & Stacking Context Debugger

Your HTML and CSS

    Preview

    Purple dashed boxes are stacking contexts; red boxes are elements whose z-index loses. Scripts in your HTML don't run.

    Which paints on top?

    Contexts in paint order

    Inside each context, later items paint on top.

      Every stacking context

      ElementCreated byz-indexInsideLayers in it

      What created them

      01

      What it does

      Renders pasted HTML, finds every stacking context and what created it, and explains why a higher z-index paints underneath.

      • Every stacking context and the property that created it
      • z-index overlaps where the higher number paints underneath, with the trapping ancestor named
      • z-index values that do nothing (not positioned)
      • Paint-order tree per context: negative, flow, z auto, positive

      02

      Private by design

      Everything happens in your browser. Nothing you type, paste or upload is sent anywhere, and it keeps working offline once the page has loaded.

      03

      What you get

      Stacking contexts with their causes, losing z-indexes with fixes, paint order and pairwise comparisons, with a Copy and a Download button on every result.

      • CSS
      • z-index
      • Stacking context
      • Debugging

      Why it matters

      z-index: 9999 that still sits under a header with z-index: 10 is one of the oldest CSS puzzles, and the answer is always the same: z-index only competes inside a stacking context. A transform, an opacity below 1, a filter, position: sticky, will-change or contain on an ancestor creates a new context, and everything inside it, whatever its z-index, is painted as one layer at the ancestor's level. DevTools doesn't show these contexts, so the fix is usually more nines.

      This debugger renders your HTML and CSS in a sandboxed frame and asks the browser for each element's computed style, so it sees exactly what the browser sees: every stacking context, the property that created it, and every z-index that's ignored because the element isn't positioned. It rebuilds the paint order from the CSS spec's layers (negative z-index, normal flow, z-index auto or 0, positive z-index), then finds overlapping elements where the higher z-index paints underneath and explains which ancestor trapped it and what it was compared with. Pick any two elements to see which paints on top and why.

      How it works

      1. InputThe HTML and CSS that misbehave
      2. In your browserRendered; every context and paint layer read from the browser
      3. OutputWhy each z-index wins or loses, and the fix

      Where it fits in a designer's workflow

      1. Plan
      2. Design
      3. Build
      4. Test
      5. Launch
      Fixing a dropdown, modal or tooltip that hides behind something.

      By the numbers

      Stacking contexts in the sample page and what traps each z-indexheader.site-header: position: sticky; holds 1; nav.menu: opacity: 0.99; holds 1; ul.dropdown: position: absolute with z-index: 9999; holds 0; section.hero: position: relative with z-index: 20; holds 1; div.hero-bg: position: absolute with z-index: -1; holds 0; div.card: transform; holds 1; div.tooltip: position: absolute with z-index: 100; holds 0; div.promo: position: relative with z-index: 1; holds 0header.site-headerposition: sticky; holds 1nav.menuopacity: 0.99; holds 1ul.dropdownposition: absolute with z-index: 9999; holds 0section.heroposition: relative with z-index: 20; holds 1div.hero-bgposition: absolute with z-index: -1; holds 0div.cardtransform; holds 1div.tooltipposition: absolute with z-index: 100; holds 0div.promoposition: relative with z-index: 1; holds 0
      Found by this tool in its sample at 768px: eight stacking contexts. Two of them, the sticky header and the transformed card, trap a z-index of 9999 and 100 below siblings with z-index 20 and 1, which is the whole bug: inside a context, z-index only competes with its neighbours. Source: MDN: Stacking context; W3C: CSS 2.2 Appendix E, elaborate description of stacking contexts.
      Show the numbers as a table
      ElementCreated byz-indexInsideLayers in it
      header.site-headerposition: sticky10html1
      nav.menuopacity: 0.99autoheader.site-header1
      ul.dropdownposition: absolute with z-index: 99999999nav.menu0
      section.heroposition: relative with z-index: 2020html1
      div.hero-bgposition: absolute with z-index: -1-1section.hero0
      div.cardtransformautohtml1
      div.tooltipposition: absolute with z-index: 100100div.card0
      div.promoposition: relative with z-index: 11html0

      How to use it

      1. Paste the HTML and CSS that misbehave.
      2. Read the red findings: each names the trapping ancestor and the fix.
      3. Pick two elements to compare.
      4. Check the context tree for unexpected contexts.

      FAQ

      Why doesn't a bigger z-index win?

      z-index only orders elements within the same stacking context. If an ancestor creates a context, the element's z-index is compared only with its siblings inside it, and the whole context is placed by the ancestor's own z-index.

      What creates a stacking context?

      The root element; position fixed or sticky; position relative or absolute with a z-index other than auto; flex and grid items with a z-index; opacity below 1; transform, translate, scale or rotate; filter and backdrop-filter; clip-path and masks; mix-blend-mode; isolation: isolate; will-change of those properties; contain: layout or paint; and container queries' size containment.

      Why is my z-index ignored?

      z-index needs the element to be positioned (relative, absolute, fixed or sticky) or to be a flex or grid item. On a static block or inline element it does nothing.

      How do I get a dropdown above everything?

      Give the trapping ancestor a higher z-index, remove the property that creates its context, or render the dropdown outside it: a portal at the end of body, or the popover attribute, which puts it in the top layer.

      Does it run my JavaScript?

      No. The HTML is rendered in a sandboxed frame with scripts removed, so state added by scripts isn't seen.

      Work with me

      Want a site that gets these right?

      I build fast, accessible websites and web apps that pass these checks from day one. Tell me about your project and I'll reply personally with honest next steps.

      All developer tools · Back to leej.uk