z-index only has an effect on an element that's positioned, meaning it has a position value other than static — a higher z-index value places an element in front of overlapping elements with a lower value, or the default auto, within the same stacking context. Crucially, z-index values are only compared directly between elements sharing the same stacking context, and certain CSS properties, like giving an element a transform, opacity below 1, or a value other than none for filter, create a brand-new, isolated stacking context for that element and its descendants, meaning a very high z-index inside one stacking context still can't beat even a low z-index belonging to a completely separate, sibling stacking context positioned in front of it.
1Understanding Z-index
z-index only has an effect on an element that's positioned, meaning it has a position value other than static — a higher z-index value places an element in front of overlapping elements with a lower value, or the default auto, within the same stacking context. Crucially, z-index values are only compared directly between elements sharing the same stacking context, and certain CSS properties, like giving an element a transform, opacity below 1, or a value other than none for filter, create a brand-new, isolated stacking context for that element and its descendants, meaning a very high z-index inside one stacking context still can't beat even a low z-index belonging to a completely separate, sibling stacking context positioned in front of it.
A surprisingly high z-index value that still fails to bring an element to the front is often caused by that element being trapped inside a separate stacking context, created by a property like transform or opacity on one of its ancestors — z-index values are only meaningfully compared within the same stacking context, not globally across the whole page.
.modal {
position: fixed;
z-index: 1000;
}
.overlay {
position: fixed;
z-index: 999;
}2Practical Example
Here is a real-world application of Z-index showing how it is used in production CSS code.
.parent {
transform: scale(1);
}
.child {
position: relative;
z-index: 9999;
}
.sibling-of-parent {
position: relative;
z-index: 1;
}3Best Practices
Follow these guidelines when working with Z-index:
1. Only apply z-index to elements that already have a non-static position value, since it has no effect otherwise
2. Investigate whether an ancestor is unintentionally creating a new stacking context, via properties like transform, opacity, or filter, when a high z-index still doesn't bring an element to the front
3. Keep z-index values organized and intentional, rather than an ever-escalating series of arbitrarily large numbers, to keep the actual stacking logic understandable
Tip: A surprisingly high z-index value that still fails to bring an element to the front is often caused by that element being trapped inside a separate stacking context, created by a property like transform or opacity on one of its ancestors — z-index values are only meaningfully compared within the same stacking context, not globally across the whole page.
.modal {
position: fixed;
z-index: 1000;
}
.overlay {
position: fixed;
z-index: 999;
}