CSS z-index and stacking contexts

May 17, 2021css-conceptscss

This post explains why elements with higher z-index values are not always in front of elements with lower z-index values.

.element {
  z-index: auto | <integer> | inherit;

According to CSS box model, each element and each string of text in a HTML document is laid out by transforming the document tree into a set of boxes, whose size, position, and stacking level on the canvas depend on the values of their CSS properties.

Since CSS2, each generated box has a position in three dimensions. In addition to their horizontal and vertical positions, boxes lie along a z-axis and are formatted one on top of the other. Z-axis positions are particularly relevant when boxes overlap visually.

CSS stacking contexts are groups of elements with a common parent that move forward or backward together in z-axis, closely related but not limited to how we use z-index property.

The z-index property only applies to positioned elements, it specifies stack level of the box in current stacking context, and whether the box establishes a stacking context. Values of`z-index has following meanings:

  • <integer>: This integer is the stack level of the generated box in the current stacking context. The box also establishes a new stacking context.
  • auto: The stack level of the generated box in the current stacking context is 0. The box does not establish a new stacking context unless it is the root element.

The root element forms the root stacking context. Other stacking contexts are generated by any positioned element (including relatively positioned elements) having a computed value of z-index other than auto. Stacking contexts are not necessarily related to containing blocks. Beside z-index, other properties may also introduce stacking contexts.

Stacking contexts can contain further stacking contexts. A stacking context is atomic from the point of view of its parent stacking context; boxes in other stacking contexts may not come between any of its boxes.

Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.

Within each stacking context, the following layers are painted in back-to-front order:

  1. the background and borders of the element forming the stacking context.
  2. the child stacking contexts with negative stack levels (most negative first).
  3. the in-flow, non-inline-level, non-positioned descendants.
  4. the non-positioned floats.
  5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  7. the child stacking contexts with positive stack levels (least positive first).

This painting order is applied recursively to each stacking context. Within each stacking context, positioned elements with stack level 0 (in layer 6), non-positioned floats (layer 4), inline blocks (layer 5), and inline tables (layer 5), are painted as if those elements themselves generated new stacking contexts, except that their positioned descendants and any would-be child stacking contexts take part in the current stacking context.