CSS Stacking Context Detailed Explanation
Description
The stacking context is an important three-dimensional concept in CSS that determines the display order of elements on the z-axis. When elements overlap, the browser follows specific rules to determine which element appears on top. Understanding stacking contexts allows for more precise control over element stacking relationships and helps avoid issues like z-index failure.
Why is Stacking Context Needed?
Imagine a page with multiple overlapping elements (like modals, dropdown menus, tooltips, etc.). Without clear rules, the browser wouldn't know how to determine their display order. Stacking contexts exist to solve this problem, creating an independent stacking "realm" where the stacking order of internal elements does not interfere with that of external elements.
Conditions for Creating a Stacking Context
An element creates a stacking context when it meets any of the following conditions:
- The document root element (
<html>) positionisabsoluteorrelative, andz-indexis notautopositionisfixedorsticky- A child of a flex container, with
z-indexnotauto opacityvalue less than1transformvalue notnone- Other properties like
filter,will-change, etc. (See the MDN documentation for the full list)
Stacking Order Rules (Important)
Within a stacking context, child elements are stacked from bottom to top (lower items appear on top) in the following order:
- The root element of the stacking context
- Positioned elements with negative
z-index(and their children) - Block-level elements (Block boxes)
- Floating elements (Floated boxes)
- Inline elements (Inline boxes)
- Positioned elements with
z-index: auto(or whose children create a stacking context) - Positioned elements with positive
z-index(and their children)
Problem-Solving Process: Analyzing a Complex Case
Let's understand these rules with an example.
- HTML Structure:
<div class="box box1">Box 1 (z-index: 10)</div>
<div class="container">
<div class="box box2">Box 2 (z-index: 100)</div>
</div>
<div class="box box3">Box 3 (z-index: 5)</div>
- CSS Styles:
.box {
position: absolute;
width: 200px;
height: 100px;
}
.box1 { background: red; z-index: 10; }
.box3 { background: blue; z-index: 5; }
.container {
position: relative;
opacity: 0.99; /* This property creates a new stacking context! */
}
.box2 {
background: green;
z-index: 100;
}
- Step-by-Step Analysis:
-
Identify Stacking Contexts:
- The
.containerelement creates a new stacking context because ofopacity: 0.99(less than 1). - The root
<html>element itself is a stacking context. .box1and.box3are positioned elements within the root stacking context.
- The
-
Compare Stacking Order:
.box1(z-index: 10) and.box3(z-index: 5) belong to the same root stacking context. According to the rules, the element with the largerz-indexis on top, so.box1is above.box3..box2belongs to the stacking context created by.container. Key Point:.box2'sz-index: 100is only effective within this new stacking context. When comparing it to the external.box1and.box3, we compare the hierarchy of their respective stacking contexts.
-
Determine Final Display Order:
- We need to compare the hierarchy of the
.containerstacking context with.box1and.box3within the root stacking context. - In the root stacking context,
.containeris a non-positioned element (it's a block-level element), and itsz-indexis the defaultauto. - According to the stacking order rules, positioned elements with
z-index: auto(Rule 6) are stacked below positioned elements with positivez-index(Rule 7). - Therefore, the entire
.containerstacking context (including its internal.box2) is stacked below.box1(z-index: 10). But is it above.box3(z-index: 5)? No, Rules 6 and 7 are consecutive; elements withz-index: autoare treated as a group, and this group is below any element with a positivez-index. - Final order (from bottom to top):
.box3(z:5) →.container(contains.box2,z-indexineffective here) →.box1(z:10)
- We need to compare the hierarchy of the
So, despite .box2 having a z-index of 100, it will ultimately appear below .box1 (z-index: 10).
Key Points & Tips
z-indexonly works on positioned elements (non-static) and when they are within the same stacking context. If an ancestor element creates a stacking context, the child element'sz-indexis "trapped" inside it.- Debugging Tips: When
z-indexdoesn't work, the first thing to check is whether an ancestor element unintentionally created a stacking context (e.g., by using properties likeopacity,transform,filter, etc.). - Best Practice: Try to keep stacking contexts flat. If complex stacking relationships are necessary, create stacking contexts intentionally and set
z-indexvalues explicitly, avoiding reliance on browser default rules.
Understanding stacking contexts is a crucial step towards mastering advanced CSS layout. It moves you from "guessing" why an element isn't on top to "knowing" why.