CSS Stacking Contexts

Intro

Today we’ll be learning about a lesser-known feature of CSS: Stacking contexts.

You may have been working on a project before and been surprised when you set the z-index for an element and it refused to move forward, remaining behind some other stubborn element.

There’s a reason for this behavior, and that reason is stacking contexts.

Stacking Context

A stacking context is essentially a group of elements whose z-index value determines their position within that group. If two elements do not share a stacking context, then they will ignore each other’s z-index values.

In this case, the stacking order is based on their relative order in the DOM (See image under “Creating a Stack”).

Creating a Stack

All of the common stacking context types.
All of the common stacking context types. Order is relative, fixed, absolute, opacity, transform.

A stacking context is created in the following cases:

  • The root stacking context (html element)
  • Absolute or relative position with a set z-index
  • Fixed position
  • Opacity less than 1
  • A set transform
  • A few other less common instances

I’ll be covering only the common instances that developers will normally encounter.

The Root Stacking Context

This case is pretty clear. Initially, all elements are part of a single stacking context under the DOM, meaning that their relative position on the z axis is determined entirely by their z-index property. If no z-index is set, their order is determine by the order in which they appear in the DOM (See image under “Creating a Stack”).

Absolute or Relative Position With a Set Z-Index

This case is the second-most common. This is almost always intentional, but occasionally, developers may try to position an element in another stacking context over some absolutely positioned element and find that it’s not possible.

Fixed Position

Another common case, but one that can be confusing. Most but not all browsers have this behavior now. Fixed position elements create their own stacking context, which without a z-index normally places it behind the document root. This can create a case of disappearing elements.

Opacity less than 1

This is a rare case, but one that everyone should be aware of. If you’re going to set opacity, then you have to know the consequence will be a new stacking context. If all you want is a translucent element, it will be more predictable if you simple set an rgba background with an alpha less than 1.

The reason for this is clear: If it did not create a new stacking context, what elements would show through the transparent element?

A Set Transform

This is a case which is more and more common lately, as CSS transforms become the norm. This often throws people off, as we assume when we scale an element it should retain its position in the flow of the document. The new stacking context can cause a transformed element to hide menus and other elements which would normally appear in front.

How Stacking Contexts Interact

Of course, the most important thing is how to apply this knowledge to create layouts and fix problems in the real world. For this reason, I’ve supplied some examples of how stacking contexts interact with each other. Most importantly, how do their children determine their z-positioning relative to other stacking context’s children?

Well, using the example from “Creating a Stack”, here’s what happens:

Z-Index Set

Z-Index on Relative Element's Children
Z-Index on Relative Element’s Children

If we set the z-index of the child elements, the result is the same as our original elements.

Z-Index Positive, Position Relative

Z-Index on Relative Element's Children - Children Are Relatively Positioned
Z-Index on Relative Element’s Children – Children Are Relatively Positioned

If we set the z-index of the child elements to a positive value, but additionally set the children’s positions to relative (creating a new stacking context for each child), then they will position completely independently of their parent, moving out in front of the other elements.

Z-Index Negative, Position Relative

Negative Z-Index on Relative Element's Children - Children Are Relatively Positioned
Negative Z-Index on Relative Element’s Children – Children Are Relatively Positioned

If we set the z-index of the child elements to a negative value, but additionally set the position to relative (creating a new stacking context for each child), then they will position completely independently of their parent, moving behind the other elements.

Z-Index Greater Than Other Stacking Context’s Children

Relative and Fixed Element with a Set Z-Index, Children With Set Z-Index Values
Relative and Fixed Element with a Set Z-Index, Children With Set Z-Index Values

In this case, we have given both the relative element, and the fixed element a z-index. The z-indices of their children do not interact, so even though the relative children are positioned ahead of the fixed children, they do not appear that way. The children are each in separate stacking contexts, though their parents share the same stacking context.

Conclusion

Stacking contexts are groups of elements whose z-index values position them along the y axis relative to each other. If an element is the root of a stacking context, its children will ignore the z-index values of the children of other stacking contexts, even if they are larger than its own.

Stacking contexts are very important when creating layouts in CSS. A lack of understanding of stacking contexts can lead to difficulty implementing relatively simple UIs, and in fixing bugs which arise commonly in today’s UIs. Stacking contexts are very commonly created when showing things like menus, popups, windows, etc. These types of UI controls are very common in web applications today, and therefore so is knowledge of stacking contexts and how they interact.