CSS Reference
z-index
Controls the stacking order of positioned elements. Higher numbers appear on top.
Last updated: October 2026
Definition: The z-index property controls the stacking order of overlapping elements. Higher values appear on top of lower values. It only works on positioned elements (relative, absolute, fixed, sticky). Understanding stacking contexts is critical to using z-index correctly.
🎬 Live Example
Three overlapping boxes with different z-index values.
💡 All three boxes are positioned with position: absolute. The z-index determines which appears on top.
Basic Syntax
.element {
position: relative; /* Required */
z-index: 10;
}
Without position, z-index does nothing. The default value is auto.
🎯 z-index Values
| Value | Meaning |
|---|---|
auto | Default. Element stacks based on DOM order. |
0 | Creates a stacking context. Sits on the baseline. |
1, 10, 100 | Positive integers. Higher is on top. |
-1 | Behind the parent's background. Use carefully. |
9999 | Common "on top of everything" value. Avoid. |
Why z-index Fails — The Position Rule
The #1 reason developers get frustrated with z-index.
/* ❌ Does nothing — element is static */
.box {
z-index: 100;
}
/* ✅ Works — element is positioned */
.box {
position: relative;
z-index: 100;
}
💡 Fix: If z-index isn't working, add position: relative first. 90% of z-index problems are solved by this.
The Defined z-index Scale
Never use random z-index values. Define a scale once and stick to it.
:root {
--z-base: 0;
--z-dropdown: 10;
--z-sticky: 100;
--z-fixed: 200;
--z-modal-backdrop: 900;
--z-modal: 1000;
--z-popover: 1100;
--z-tooltip: 1200;
--z-toast: 1300;
}
.dropdown { z-index: var(--z-dropdown); }
.navbar { z-index: var(--z-sticky); }
.modal { z-index: var(--z-modal); }
.toast { z-index: var(--z-toast); }
This prevents "z-index wars" — the situation where every developer uses bigger numbers than the last one to force elements on top.
Stacking Contexts
A stacking context is a scoped area where z-index values only compete with other elements in the same context.
What creates a stacking context:
- Positioned element with a z-index value other than
auto. - Element with
transform,filter, orperspective. - Element with
opacityless than 1. - Element with
mix-blend-modeother than normal. - Element with
isolation: isolate. - Element with
will-changeon certain properties. - Flex or Grid items with
z-indexother than auto.
Consequence: A child element can never appear on top of a sibling of its parent's stacking context, no matter how high its z-index is. The parent's stacking context is the ceiling.
Common Real-World z-index Values
/* Dropdown menus */
.dropdown-content {
position: absolute;
z-index: 10;
}
/* Sticky header */
.header {
position: sticky;
top: 0;
z-index: 100;
}
/* Fixed sidebar */
.sidebar {
position: fixed;
z-index: 200;
}
/* Modal backdrop */
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 900;
}
/* Modal itself */
.modal {
position: fixed;
z-index: 1000;
}
/* Toast notification */
.toast {
position: fixed;
z-index: 9999;
}
How to Fix z-index Problems
A systematic debugging approach:
- Check position. The element must have
position: relative,absolute,fixed, orsticky. - Check the parent's stacking context. Open DevTools and look at the ancestors. If any have
transform,filter,opacity: < 1, or a z-index, they create a stacking context. - Check sibling order. Elements with the same z-index stack by DOM order. If your element is earlier in the DOM, it's behind.
- Check for negative z-index ancestors. A parent with negative z-index puts its children behind the parent's siblings.
- Use the DevTools "Layers" panel. Chrome's Layers panel visualizes stacking contexts and helps spot the culprit.
🎯 Common z-index Use Cases
| Element | Typical z-index |
|---|---|
| Dropdown menu | 10 |
| Sticky header | 100 |
| Fixed sidebar | 200 |
| Back-to-top button | 500 |
| Modal backdrop | 900 |
| Modal dialog | 1000 |
| Popover / tooltip | 1100 |
| Toast notification | 1300 |
⚠️ Common Mistakes
- Using z-index without position. z-index only works on positioned elements. Add
position: relativeif needed. - Random numbers everywhere. Use a defined scale with CSS variables.
- Fighting a stacking context. A parent with
transform,filter, oropacity: < 1creates a stacking context that caps all child z-index values. - Assuming z-index is global. It's scoped to the stacking context. Two elements in different contexts can't be compared directly.
- Using
9999for everything. Once you need 10000, you're stuck. Use a defined scale. - Negative z-index for elements you want visible. It hides the element behind its parent's background. Rarely useful.
- Not testing modal overlays on iOS. iOS has different stacking behavior for fixed elements with transforms. Test on real devices.
♿ Accessibility Notes
- z-index doesn't affect screen readers. Reading order is determined by DOM order, not visual stacking.
- Overlapping content can hide interactive elements. If a modal covers buttons, keyboard users may still focus those hidden buttons unless you manage focus.
- Modals need focus trapping. Positioning alone doesn't handle keyboard focus. Use
<dialog>or manage focus with JavaScript. - Sticky headers must not cover content. A sticky header with a high z-index can hide form fields. Test with keyboard navigation.
- Visual order should match reading order. z-index lets you place things anywhere, but keyboard and screen reader order should still make sense.
❓ Frequently Asked Questions
What is the CSS z-index property?
z-index controls the stacking order of positioned elements. Higher values appear on top of lower values. It only works on positioned elements — relative, absolute, fixed, or sticky.
Why is my z-index not working?
The most common reason is that the element isn't positioned. Add position: relative, absolute, fixed, or sticky. The second most common reason is that the element is inside a stacking context that prevents it from being compared with the target.
What is a stacking context?
A stacking context is a local scoped area where z-index values are relative only to other elements in the same context. It's created by positioned elements with z-index, transform, filter, opacity less than 1, and other properties.
What z-index values should I use?
Use a defined scale, not random numbers. Example: base content (0), dropdowns (10-100), sticky headers (100-500), modals (1000+), toasts (9999). Define these as CSS variables so the whole team uses the same values.
Can z-index be negative?
Yes. Negative z-index places the element behind its parent's background. Use it sparingly — it often causes confusion and can hide content behind other elements.