Syntax
z-index: number;Examples
z-index in an Ordinary Block Layout
A common mistake - z-index silently does nothing without position set.
/* Demo setup: sizing, structure or neutral surfaces. */
.behind,.in-front{width:14rem;height:5rem;padding:1rem;color:white}.behind{background:#b45309}.in-front{background:#166534;margin-top:-2rem;margin-left:3rem}
.behind {
z-index: 999; /* does not establish stacking for this ordinary static block; flex/grid items differ */
}
.in-front {
position: relative; /* now z-index actually applies */
z-index: 999;
}- The examples overlap so painting order can be observed.
- A positioned block can use z-index in this ordinary block layout.
- Flex and grid items can also use z-index without positioning, so the rule is not universally limited to positioned elements.
HTML used by this example
<div class="preview-stack"><div class="behind">Static block</div><div class="in-front">Positioned block</div></div>The Stacking Context Trap
Why a huge z-index sometimes still loses to a smaller one.
/* Demo setup: sizing, structure or neutral surfaces. */
.preview-stack{min-height:12rem}.parent-a,.parent-b{width:16rem;height:6rem;color:white;padding:1rem}.parent-a{background:#7c3aed}.parent-b{background:#166534;margin-top:-3rem;margin-left:4rem}.child{background:#b45309;padding:1rem;width:18rem}
.parent-a {
position: relative;
z-index: 1; /* creates a new stacking context */
}
.parent-a .child {
position: relative;
z-index: 9999; /* only competes WITHIN parent-a's stacking context */
}
.parent-b {
position: relative;
z-index: 2; /* parent-b beats parent-a entirely, so ALL its children render above,
regardless of how high a z-index .child has inside parent-a */
}- The two parents create separate stacking contexts.
- The child’s large value competes inside parent A, not directly against parent B.
- Where they overlap, parent B can cover the child because its parent context is above parent A.
HTML used by this example
<div class="preview-stack"><div class="parent-a"><div class="child">Child: z-index 9999 inside parent A</div></div><div class="parent-b">Parent B: higher outer context</div></div>Parameters and values
- z-index (number | auto): Stacking order among elements in the same stacking context
Best practices
- Remember z-index only has an effect on positioned elements (position other than static) - set position: relative (or another value) first
- Understand that properties like opacity < 1, transform, and filter also create new stacking contexts, which can trap z-index values unexpectedly
- Use a documented, limited scale of z-index values across a project (like 10, 20, 30, 100 for modals) rather than arbitrary huge numbers, to keep stacking predictable
- When a high z-index "does not work," the real cause is almost always an unexpected stacking context on an ancestor, not the z-index value itself being too low
Browser compatibility
- chrome
- Yes
- firefox
- Yes
- safari
- Yes
- edge
- Yes
These are the existing reference’s support labels, not tested minimum versions. Individual values and APIs can have different support. Check the linked specification before choosing a browser target.
CSS specifications (modules)