Z - Index & Stacking Order
Control which elements appear on top with z-index — stacking contexts, stacking order, and common z-index patterns.
Z-Index & Stacking Order
When elements overlap, z-index controls which one appears on top. Think of it as a layer system — higher z-index = closer to the viewer.
The Default Stacking Order
Without any z-index, elements stack in this order (back to front):
- Root element background
- Non-positioned elements (in HTML source order)
- Positioned elements (in HTML source order)
Later elements in the HTML sit on top of earlier ones.
Using z-index
.element {
position: relative; /* z-index only works on positioned elements! */
z-index: 10;
}
Important Rule: z-index Only Works on Positioned Elements
/* This does NOTHING: */
.element {
z-index: 999; /* Ignored! No position set */
}
/* This works: */
.element {
position: relative; /* or absolute, fixed, sticky */
z-index: 999;
}
z-index Values
| Value | Behavior |
|---|---|
auto (default) | Same as parent's stacking context |
| Positive (1, 10, 100) | Above elements with lower z-index |
0 | Creates a stacking context at the base layer |
| Negative (-1, -10) | Behind non-positioned elements |
.behind { position: relative; z-index: -1; }
.base { position: relative; z-index: 0; }
.above { position: relative; z-index: 10; }
.on-top { position: relative; z-index: 100; }
/* Visual stacking (back to front):
.behind → .base → .above → .on-top */
Stacking Contexts
A stacking context is a group of elements that stack together as a unit. z-index values only compete within the same stacking context.
<div class="parent-a" style="position:relative; z-index:1;">
<div class="child" style="position:relative; z-index:999;">
I'm at z-index 999!
</div>
</div>
<div class="parent-b" style="position:relative; z-index:2;">
<div class="child" style="position:relative; z-index:1;">
I'm only z-index 1, but I'm ON TOP!
</div>
</div>
/* parent-b (z-index: 2) is above parent-a (z-index: 1).
ALL children of parent-b are above ALL children of parent-a,
regardless of their individual z-index values! */
What Creates a Stacking Context?
- The root element (
<html>) position: relative/absolute/fixed/stickywithz-indexother thanautoopacityless than 1transform,filter, orperspectiveset to anythingisolation: isolate
A Common z-index Scale
:root {
--z-dropdown: 100;
--z-sticky: 200;
--z-fixed: 300;
--z-modal-backdrop: 400;
--z-modal: 500;
--z-popover: 600;
--z-tooltip: 700;
}
.dropdown { z-index: var(--z-dropdown); }
.header { z-index: var(--z-fixed); }
.modal { z-index: var(--z-modal); }
.tooltip { z-index: var(--z-tooltip); }
Using a scale with gaps (100, 200, 300…) makes it easy to insert new layers later.
Debugging z-index
- Check that the element has a
positionvalue (notstatic) - Check the parent's stacking context — a parent with a lower z-index limits all its children
- Use Chrome DevTools → 3D View (Layers panel) to visualize the stack
- Avoid z-index wars (99999) — use a systematic scale
Key Takeaways
z-indexcontrols stacking order — higher values appear on top- Only works on positioned elements (relative, absolute, fixed, sticky)
- z-index values only compete within the same stacking context
- Parent stacking contexts limit their children's stacking
- Use a systematic z-index scale with gaps for maintainability
- Avoid z-index: 99999 — it's a sign of structural problems