Understand how CSS stacking contexts work, how z-index controls layer order for positioned elements, and learn common patterns for managing overlapping content.
The z-index property controls the stacking order of elements that overlap. Elements with a higher z-index value are rendered in front of elements with a lower value.
Critical rule: z-index only works on positioned elements — that is, elements with position set to relative, absolute, fixed, or sticky. It has no effect on statically positioned elements.
.behind {
position: relative;
z-index: 1;
}
.in-front {
position: relative;
z-index: 10;
}Without an explicit z-index, positioned elements stack in source order — later elements in the HTML appear on top of earlier ones. The z-index property lets you override this default behavior.
Values can be any integer, including negative numbers. A negative z-index places the element behind elements with z-index: auto (the default).
/* A stacking context is created by: */
/* 1. The root element (<html>) */
/* 2. position + z-index (not auto) */
.modal {
position: fixed;
z-index: 1000;
}
/* 3. opacity less than 1 */
.faded {
opacity: 0.9; /* creates a stacking context */
}
/* 4. transform, filter, or perspective */
.card {
transform: translateZ(0); /* creates a stacking context */
}
/* 5. isolation: isolate */
.isolated {
isolation: isolate; /* explicitly creates a stacking context */
}
/* Common z-index scale for projects */
/* base: 1 */
/* dropdown: 100 */
/* sticky: 200 */
/* overlay: 300 */
/* modal: 400 */
/* toast: 500 */A stacking context is a three-dimensional conceptualization of HTML elements along the z-axis. Each stacking context is self-contained: z-index values inside one context are independent of values in another context.
This is the most common source of confusion with z-index. Consider this scenario:
<div class="parent-a" style="position: relative; z-index: 1;">
<div class="child" style="position: relative; z-index: 999;">I'm trapped!</div>
</div>
<div class="parent-b" style="position: relative; z-index: 2;">
I will always be on top of child!
</div>Even though the child has z-index: 999, it can never appear above parent-b because parent-a (with z-index: 1) creates a stacking context. The child's high z-index only matters within parent-a's context.
Tips for managing stacking:
z-index: 99999.isolation: isolate to create a stacking context without side effects.opacity, transform, and filter also create stacking contexts.Why might an element with z-index: 9999 still appear behind another element with z-index: 2?