stacking context in CSS: why a high z-index can still lose

A stacking context isolates a group of elements: a huge z-index can still end up stuck behind another block with a far smaller one.
4 min read
Believemy logo

Two elements have a z-index of 9999 and 10, and everything suggests the first one will sit in front of the second. Yet on screen, the opposite happens. This kind of surprise is almost always the symptom of a stacking context: a subgroup of elements that stack among themselves, isolated from the rest of the page, in a way that z-index alone cannot escape.

Understanding this mechanism becomes essential as soon as an interface layers elements on top of each other: a menu above the content, a modal above everything, a tooltip that must stay visible. Without it, debugging an element "hidden behind another one" turns into a series of random guesses with ever larger z-index values, often with no effect at all.


Definition

A stacking context is a grouping of HTML elements whose display order relative to each other, along the axis that runs toward the screen or into the page, is decided independently from the rest of the document. Inside a context, z-index values compare normally against each other. But an entire context, together with all its children, stacks as a single block against elements outside it, as if it were one object.


What creates a new context

The document root, the html element, always creates a stacking context. Beyond that, several CSS declarations create a new one on whichever element carries them, even without asking for it explicitly.

DeclarationCondition
position: relative or absolute with z-indexz-index other than auto
position: fixed or stickyalways, even without z-index
opacityvalue below 1
transformvalue other than none
filter, will-change, mix-blend-modevalue other than the initial one

This list is not exhaustive, but it covers the vast majority of cases you will run into in practice. The common thread: these are almost always properties tied to animation or visual rendering, two areas where the browser benefits from isolating an element into its own rendering layer.


Why a high z-index can still lose

Here is the central trap: an element's z-index is only compared against other elements inside its own stacking context. If its parent has itself created a context, for instance with an opacity below 1, then the child's final position is first fixed by where the parent sits in the outer context, before the child's own z-index even comes into play.

CSS
.parent-a {
  position: relative;
  z-index: 1;
  opacity: 0.99; /* creates a stacking context */
}

.parent-a .child {
  position: relative;
  z-index: 9999; /* huge, but trapped inside the parent's context */
}

.parent-b {
  position: relative;
  z-index: 2; /* sits in front of all of .parent-a, no matter its content */
}

In this example, .child can never sit in front of .parent-b, whatever value its z-index has, because it is .parent-a as a whole, with a z-index of 1, that gets compared to .parent-b and its z-index of 2.

Good to knowBefore raising a z-index that seems to do nothing, check whether one of its parents has an opacity below 1, a transform, or positioning combined with a z-index. That is almost always the real cause, not the z-index value itself.


Stacking context is not layout

A stacking context should not be confused with a flexible or grid container, which organizes the position of elements within the plane of the page. A stacking context instead organizes their order along the depth axis, the one that decides what sits in front or behind. The two can trigger together on the same element, for instance a container with a z-index that also becomes a stacking context, but they are two independent mechanisms answering two different questions.


Diagnosing stacking that looks illogical

When an element stays stuck behind another despite a high z-index, the most reliable method is to walk up the tree of parents one by one, looking for whichever one carries an opacity, a transform, a filter, or positioning combined with a z-index. Modern browser developer tools often show stacking contexts directly in a three-dimensional inspection panel, which saves you from guessing.


FAQ

QuestionShould stacking contexts be avoided?

No, they are essential and often created on purpose, for example to guarantee that a modal always sits above everything else. The problem is not their existence, but not knowing where they sit within the page.

QuestionCan an element without positioning create a stacking context?

Yes, several properties create a context without any positioning at all, notably an opacity below 1, a transform, or a filter: positioning combined with z-index is only one case among others.

QuestionDoes a negative z-index take an element out of its stacking context?

No, a negative z-index only places the element lower in the stacking order of its own context, often behind its parent's background, but it remains trapped inside that same context like any other value.

Related terms

Discover our hTML and CSS glossary

Browse the terms and definitions most commonly used in HTML and CSS development.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.