Skip to content

z-index & Stacking Contexts Explained

How CSS stacking contexts actually work: what creates one, the painting order inside it, how flex and grid children earn z-index without position, and which values are worth using.

z-index only competes inside a stacking context, and half the CSS you already write creates one by accident. Know what forms a context, the order browsers paint layers within it, and the small set of values worth reaching for.

Reference table · 26 entries
26 of 26 rows
Stacking contexts
Document rootThe html element carries the root stacking context; every element on the page participates in it.:rootThe root background is the floor of the page — a z-index: -1 child paints behind text but never behind the html background.
Positioned + integer z-indexA positioned element with an integer z-index forms a new stacking context that traps its descendants.position: relative; z-index: 2;The position value alone does not create the context — the integer z-index does.
Positioned + z-index: autoA positioned element with z-index: auto stays in its parent's stacking context and paints in the auto layer.position: absolute; z-index: auto;auto is not 0: auto creates no context, 0 creates one, yet both paint at the same level.
opacity < 1Any opacity below 1 forces the element into its own stacking context so the group composites as one layer.opacity: 0.99;A fade that ends at 0.99 instead of 1 permanently changes stacking — descendant z-index cannot escape it.
transformAny transform value other than none creates a stacking context and a compositing layer.transform: translateZ(0);The old translateZ(0) GPU hack silently traps descendant z-index forever after.
filter / backdrop-filterA filter or backdrop-filter value other than none makes the element a stacking context.filter: blur(0px);Even a no-op blur(0px) counts; will-change: transform or filter triggers the same before anything animates.
isolationCreates a stacking context and does nothing else — the side-effect-free way to fence off a component.isolation: isolate;Reach for this instead of z-index hacks when a third-party widget's values must stay inside your layout.
position: fixed / stickyFixed and sticky elements form stacking contexts even with z-index: auto.position: fixed;A context is not a crown: a fixed header still needs z-index to beat later positioned siblings — and an ancestor with transform makes it behave like absolute.
Other triggersmix-blend-mode other than normal, clip-path, mask, perspective, and contain: paint / layout / content each create a context.mix-blend-mode: difference;They stack up: an element with both opacity: 0.9 and a transform is still exactly one new context.
Painting order
1. Backgrounds & bordersThe stacking context element's own background and borders paint first, behind everything inside it.background: #0b1020; border: 1px solid #333;This is the floor of the context — no descendant ever paints below it.
2. Negative z-indexChildren with negative z-index paint behind in-flow content, ordered from most negative up.z-index: -1;The standard way to tuck a decorative layer behind text without leaving the parent.
3. In-flow blocksNon-positioned block descendants paint backgrounds and borders in tree order.display: block;Their text does not paint here — inline content waits for a later step.
4. FloatsNon-positioned floats paint after in-flow block backgrounds, before inline content.float: left;A float sits above block backgrounds but below inline text — the classic wrap-around look.
5. Inline contentAll inline-level content paints after floats, on top of everything so far.display: inline;That is why plain text renders over a floated sibling's background.
6. z-index: 0 / autoPositioned elements with z-index 0 or auto paint after all of the above, in tree order.position: relative; z-index: auto;Same paint level as 0, different containment — 0 fences descendants, auto does not.
7. Positive z-indexThe top layer inside the context: higher integers paint over lower ones, ties break by tree order.z-index: 1;These values only compete inside their own context — they never reach over a sibling context.
Flex & grid children
Flex itemsFlex items honor z-index with no position value at all..list { display: flex; } .item { z-index: 3; }Advice that z-index needs position: relative predates flexbox — it stopped being true there.
Grid itemsGrid items paint by z-index while position: static, which is how overlapping grid areas choose order..board { display: grid; } .cell { z-index: 2; }Overlapping areas with no z-index fall back to source order.
z-index: auto on itemsA flex or grid item with z-index: auto creates no context; paint order follows order-modified source order.order: -1;Changing order changes which overlapping item paints on top — reorder and the overlap flips.
Integer z-index on itemsA flex or grid item with an integer z-index becomes a stacking context even at position: static.z-index: 2;Same rule as positioned elements: values inside the item cannot escape the item.
Values that matter
autoPaints at the base auto level and creates no stacking context of its own.z-index: auto;Reset with auto, not 0, when you want to dissolve containment as well as level.
0Creates a stacking context at the base level — a containment fence that changes no paint order.z-index: 0;position: relative + z-index: 0 isolates a component without joining any arms race.
1Beats every auto and 0 sibling inside the same context.z-index: 1;One level above baseline is usually all a local overlay or badge needs.
9999A smell, not a scale: it wins today's fight and starts tomorrow's escalation.z-index: 9999;A 9999 modal inside a low-level context still loses to any sibling of a higher context — the ancestor's level caps it.
Integers onlyz-index accepts integers and auto; nothing else parses.z-index: 1.5;A decimal is an invalid value, so the whole declaration is dropped and the earlier one wins.
BoundsValues clamp to ±2147483647, the 32-bit signed integer ceiling.z-index: 2147483647;Browsers clamp out-of-range values, so 99999999 paints exactly like the max — the cap ends every escalation.