CSS stacking contexts: What they are and how they work
Stacking contexts are an aspect of CSS that trips up most developers. I don't think I fully understood them until I wrote the layout chapter of CSS Master. Sure, I understood that
position to be something besides
static. But that's about as far as my comprehension went, even after reading Philip Walton's What No One Told You About Z-Index fiftyleven times.
That's no shade to Philip, by the way. Like I said: stacking contexts are tricky.
So what is a stacking context? A stacking context is an element that contains a set of layers. This can be a root stacking context, as created by the
html element. Or it can be a local stacking context, as created by specific properties and values.
"Contains a stack of layers" is a weird phrase, but a simple concept. Within a local stacking context, the
z-index values of its children are set relative to that element rather than to the document root. Layers outside of that context — i.e. sibling elements of a local stacking context — can't sit between layers within it.
Here's an example. Use the toggle to switch in and out of a local stacking context for A.
In this example,
#a p (
Child of A) has
z-index: 1 applied, while
z-index values of
#a p is positioned and has a positive stack level, it sits on top of both
#b within the root stacking context.
transform: none to
transform: scale(1) for
#a, however, triggers a local stacking context. Now the
z-index: 1 value for
#a p is now calculated relative to
#a instead of the document root.
Stacking contexts — whether local or root — follow a set of rules that determine the stacking and painting order of elements. Children of a stacking context are painted from bottom to top in the following order.
- Elements with a negative stack level, typically elements with
- Elements with a
- Elements with a stack level of 0, typically positioned elements with a
- Elements with positive stack levels, e.g. a positioned element with a
Two elements with the same stack level are layered based on their source order. Successive elements stack on top of their predecessors.
A handful of CSS properties and values trigger a new stacking context. These include
opacity when its value is less than 1 (e.g.:
filter when its value is something other than
mix-blend-mode when its value is something other than
transform property, as you may have guessed, is a property that can trigger a stacking context — but only when its value isn't
none. This includes identity transforms1, such as
In the example above,
#b have the same stack level, but
#b is the second element in the source. When
transform: scale(1) is applied,
#a p becomes contained within the local stacking context of
#a. As a result,
#b rises to the top of the stack.