Stacking Context
The Problem
Stacking context is the most misunderstood concept in CSS. AI agents routinely escalate z-index values to absurd numbers (99999) without understanding why elements still appear behind others. The root cause is almost always that elements live in different stacking contexts, and no amount of z-index increase can break out of a parent's stacking context.
The Solution
A stacking context is an isolated layering group. Elements within one stacking context are compared against each other for z-ordering, but they are never compared against elements in a different stacking context. Understanding what creates a stacking context, and using the isolation property to create them intentionally, eliminates z-index wars.
What Creates a Stacking Context
The following properties create a new stacking context on an element:
Always creates a stacking context
- The root element (
<html>) position: fixedposition: sticky
Creates a stacking context when a condition is met
position: relativeorposition: absolutewithz-indexother thanautoopacityless than1transformwith any value other thannonefilterwith any value other thannonebackdrop-filterwith any value other thannoneperspectivewith any value other thannoneclip-pathwith any value other thannonemask/mask-image/mask-borderwith any value other thannonemix-blend-modewith any value other thannormalisolation: isolatewill-changespecifying any of the above propertiescontain: layout,contain: paint, orcontain: strict
Code Examples
The Classic z-index Bug
.sidebar {
position: relative;
z-index: 1;
}
.sidebar .dropdown {
position: absolute;
z-index: 99999; /* Will NOT appear above .main-content */
}
.main-content {
position: relative;
z-index: 2;
}
In this example, .dropdown has z-index: 99999 but still renders behind .main-content. This happens because .sidebar creates a stacking context with z-index: 1. The dropdown is trapped inside that stacking context. From the perspective of .main-content (z-index: 2), the entire .sidebar group has z-index 1.
Fix: Remove the Parent's Stacking Context
.sidebar {
position: relative;
/* Remove z-index to avoid creating a stacking context */
}
.sidebar .dropdown {
position: absolute;
z-index: 10;
}
.main-content {
position: relative;
/* No z-index needed */
}
The isolation Property
isolation: isolate is the cleanest way to create a stacking context. It does exactly one thing: creates a new stacking context. No side effects, no visual changes.
.card {
isolation: isolate; /* Creates stacking context */
}
.card .background {
position: absolute;
inset: 0;
z-index: -1; /* Stays behind card content but inside card's context */
}
.card .content {
position: relative;
/* z-index: auto, but still above .background due to DOM order */
}
<div class="card">
<div class="background"></div>
<div class="content">Card text</div>
</div>
Preventing Component Leakage
Use isolation: isolate on component root elements to prevent z-index from leaking out.
/* Each component is self-contained */
.modal-overlay {
isolation: isolate;
position: fixed;
inset: 0;
z-index: 100;
}
.tooltip {
isolation: isolate;
position: absolute;
}
.dropdown-menu {
isolation: isolate;
position: absolute;
}
Accidental Stacking Contexts
Properties that seem unrelated to layering can silently create stacking contexts.
/* This creates a stacking context! */
.fading-element {
opacity: 0.99;
}
/* This also creates a stacking context! */
.animated-element {
transform: translateZ(0); /* Often added for "GPU acceleration" */
}
/* This too! */
.blurred-element {
filter: blur(0px);
}
Any of these will trap child z-index values inside the element's stacking context.
Debugging Stacking Context Issues
Step-by-step diagnosis
- Identify the element that is layered incorrectly.
- Walk up the DOM tree from that element to the root.
- For each ancestor, check if it creates a stacking context (use the list above).
- Find the stacking context boundary where the layering breaks.
- Either remove the unnecessary stacking context, or restructure z-index values to work within the existing contexts.
Browser DevTools
In Chrome DevTools, the Layers panel (More Tools > Layers) visualizes stacking contexts. Firefox DevTools shows stacking context information in the Layout panel.
Common AI Mistakes
- Escalating z-index values. When an element does not appear on top, AI agents increase z-index to large numbers. This never solves stacking context issues. The fix is to understand which stacking contexts the elements belong to.
- Not knowing that
opacity,transform, andfiltercreate stacking contexts. Addingopacity: 0.99ortransform: translateZ(0)for performance can break z-index behavior of child elements. - Using z-index on non-positioned elements.
z-indexonly works on positioned elements (relative,absolute,fixed,sticky) and flex/grid items. On a statically positioned element, it has no effect. - Not using
isolation: isolatefor component boundaries. Every reusable component with internal z-index should useisolation: isolateto prevent its z-index values from leaking into the parent context. - Adding
position: relative; z-index: 1as a general "fix". This creates a new stacking context, which may fix the immediate issue but traps all descendant z-index values and causes new problems elsewhere.
When to Use
Use isolation: isolate when
- Building reusable components that use z-index internally
- You need a stacking context without any visual side effect
- You want to contain
z-index: -1elements within their parent - You want to prevent mix-blend-mode from bleeding through
Use z-index when
- Controlling the order of positioned elements within the same stacking context
- Layering overlays, modals, and dropdowns at the page level
Audit stacking contexts when
- A z-index value "does not work"
- An element with a high z-index appears behind one with a lower z-index
- Adding
opacity,transform, orfiltercauses unexpected layering changes