How z-index Works
Although it may not be immediately obvious, the elements in an HTML document are generated in three dimensions. Besides being aligned on the x- and y- axes, elements can lie on the z-axis, which controls their position in the third dimension.
Properties such as margin, float, and the offset properties control how the element sits on the x- and y- axes. The z-index
property solely controls how elements are arranged on this z-axis.
The z-index Property #
The z-index
property specifies two things -
- The stacking level of the current element
- If the current element establishes a new stacking context
The property only applies to positioned elements. That is, elements that have a position
of relative
, absolute
, or fixed
.
There are three potential values for the z-index
property -
Value | Description |
---|---|
auto |
Sets the stacking level to 0 and does not establish a new stacking context |
<integer> |
Sets the stacking level to the integer and establishes a new stacking context |
inherit |
Sets the stacking level to the same as it’s parent element and does not establish a new stacking context |
z-index: auto | <integer> | inherit
Stacking Level #
The stacking level is the value on the z-axis that the current element is on. Higher numbers indicate that the element is higher on the stack of elements and closer to the surface of the screen.
If not specified by the z-index property, the stacking level of an element is established according to it’s arrangement in the document tree. Elements that are declared later in the document have a higher stacking level by default.
Calculating Stacking Level #
In addition to the specified z-index
, the stacking level of an element is controlled by a number of factors. Elements are stacked in the following order.
Position | Description | CSS |
---|---|---|
1 (bottom) | The element forming the stacking context | z-index: <integer> |
2 | Child elements with negative stack levels | `z-index: |
3 | In-flow, non-inline, non-positioned child elements | display: /* not inline */``position: static |
4 | Non-positioned floating child elements | `float: left |
5 | In-flow inline, non-positioned child elements | display: /* inline */``position: static |
6 | Child elements with stacking level of 0 | `z-index: auto |
7 (top) | Child elements with positive stack levels | `z-index: |
Stacking Context #
When we specify the stacking level for an element using the z-index
property, we are not always specifying the stacking level of the element in relation to every other element on the page. The element’s stacking level is only in relation to its stacking context.
This can lead to some bizarre situations in which an element with a higher number z-index is not always necessarily “above” an element with a lower z-index.
Stacking context can be explained by the following rules.
1. The default stacking context is the root element #
The default stacking context for any HTML document is the root <html>
element. Therefore, unless new stacking contexts are created, the stacking level of an element is, by default, in relation to every other element on the page.
2. Establish a new stacking context with the z-index property #
We establish a new stacking context by setting the z-index of an element to any integer. This has the effect of, firstly, setting the current element’s stacking level to that integer, and secondly, creating a new stacking context.
The new stacking context applies to any children of that element. Their stacking levels are now only within that stacking context, not the root stacking context.
In the example below, .foo
belongs to stacking context 1, whereas .bar
belongs to stacking context 2.
3. Elements cannot be stacked above (or below) the parent element’s stacking level #
When the parent element’s stacking level is set, that means that its children also cannot be stacked above or below that level (in relation to the parent element's stacking context).
In the example below, even though .bar
has a higher z-index than .baz
, it still shows "below" it. This is because, in stacking context 1, .bar
cannot go above or below stacking level 1.
.foo { z-index: 1; }
.bar { z-index: 1000; }
.baz { z-index: 2; }