Advanced20 min read

Z-Index & Stacking Context

Understand how CSS stacking contexts work, how z-index controls layer order for positioned elements, and learn common patterns for managing overlapping content.

How Z-Index Works

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.

css
.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).

Stacking Context Creation

css
/* 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   */

Stacking Context Gotchas

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:

html
<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:

  • Keep your z-index values in a defined scale (e.g., 100, 200, 300).
  • Avoid arbitrary large values like z-index: 99999.
  • Use isolation: isolate to create a stacking context without side effects.
  • Remember that 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?

Ready to practice?

Create your free account to access the interactive code editor, run challenges, and track your progress.