概述
在 CSS2.1 规范中,每个盒模型的位置是三维的,分别是平面画布上的 x 轴,y 轴以及表示层叠的 z 轴。
层叠上下文即元素在某个层级上 z 轴方向的排列关系。
其中包含几个重要的概念:层叠上下文(Stacking Context)、层叠等级(Stacking Level,也叫层叠水平)、层叠顺序(Stacking Order)、z-index
层叠上下文
层叠上下文是一个抽象性的概念,类似 BFC ,具象化理解就是,网页中的元素大多是普通元素,而一旦普通元素拥有了层叠上下文就能变成 层叠上下文元素 ,能够覆盖在普通元素上方进行显示

层叠上下文 1 (Stacking Context 1) 是由文档根元素形成的, 层叠上下文 2 和 3 (Stacking Context 2, 3) 都是层叠上下文 1 (Stacking Context 1) 上的层叠层。 他们各自也都形成了新的层叠上下文,其中包含着新的层叠层。
形成条件
- 文档根元素(< html >);
- position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index 值不为 auto 的元素;
- position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);
- flex (flex) 容器的子元素,且 z-index 值不为 auto;
- grid (grid) 容器的子元素,且 z-index 值不为 auto;
- opacity 属性值小于 1 的元素(参见 the specification for opacity);
- mix-blend-mode 属性值不为 normal 的元素;
- 以下任意属性值不为 none 的元素:
- transform
- filter
- backdrop-filter
- perspective
- clip-path
- mask / mask-image / mask-border
- isolation 属性值为 isolate 的元素;
- will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章);
- contain 属性值为 layout、paint 或包含它们其中之一的合成值(比如 contain: strict、contain: content)的元素。
详情参考 MDN:层叠上下文 - CSS(层叠样式表) | MDN
特性
层叠上下文元素有如下特性:
- 层叠上下文的层叠水平要比普通元素高;
- 层叠上下文可以阻断元素的混合模式;
- 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文。
- 每个层叠上下文和兄弟元素独立,也就是当进行层叠变化或渲染的时候,只需要考虑后代元素。
- 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。
层叠等级
层叠等级 (层叠水平, Stacking Level) 表示同一个层叠上下文中元素在 z 轴上的显示顺序的概念;
所有的元素都有层叠水平,包括层叠上下文元素,层叠上下文元素的层叠水平可以理解为官员的职级,1 品 2 品,县长省长之类
- 普通元素的层叠等级优先由其所在的层叠上下文决定
- 层叠等级的比较只有在同一个层叠上下文元素中才有意义
- 在同一个层叠上下文中,层叠等级描述定义的是该层叠上下文中的元素在 Z 轴上的上下顺序
注意,层叠等级并不一定由 z-index 决定,只有定位元素的层叠等级才由 z-index 决定,其他类型元素的层叠等级由层叠顺序、他们在 HTML 中出现的顺序、他们的父级以上元素的层叠等级一同决定,详细的规则见下面层叠顺序的介绍
z-index
在 CSS 2.1 中, 所有的盒模型元素都处于三维坐标系中。 除了我们常用的横坐标和纵坐标, 盒模型元素还可以沿着 "z 轴 " 层叠摆放, 当他们相互覆盖时, z 轴顺序就变得十分重要。
z-index 只适用于定位的元素,对非定位元素无效,它可以被设置为正整数、负整数、0、auto,如果一个定位元素没有设置 z-index,那么默认为 auto;
元素的 z-index 值只在同一个层叠上下文中有意义。如果父级层叠上下文的层叠等级低于另一个层叠上下文的,那么它 z-index 设的再高也没用。所以如果你遇到 z-index 值设了很大,但是不起作用的话,就去看看它的父级层叠上下文是否被其他层叠上下文盖住了。
层叠顺序
层叠上下文和层叠等级是概念,而层叠顺序是规则,是元素排列遵循的一系列方式

css3 后的改进版:
不过上面图示的说法有一些不准确,按照 W3 官方 的说法,准确的 7 层为:
- the background and borders of the element forming the stacking context.
- the child stacking contexts with negative stack levels (most negative first).
- the in-flow, non-inline-level, non-positioned descendants.
- the non-positioned floats.
- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
- the child stacking contexts with positive stack levels (least positive first).
稍微翻译一下:
- 形成堆叠上下文环境的元素的背景与边框
- 拥有负 z-index 的子堆叠上下文元素 (负的越高越堆叠层级越低)
- 正常流式布局,非 inline-block,无 position 定位(static 除外)的子元素
- 无 position 定位(static 除外)的 float 浮动元素
- 正常流式布局, inline-block 元素,无 position 定位(static 除外)的子元素(包括 display:table 和 display:inline )
- 拥有 z-index:0 的子堆叠上下文元素
- 拥有正 z-index: 的子堆叠上下文元素(正的越低越堆叠层级越低)
层叠先后判断方法
当元素发生层叠的时候,其覆盖关系遵循下面 2 个准则:
- 谁大谁上:当具有明显的层叠水平标示的时候,如识别的 z-indx 值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。通俗讲就是官大的压死官小的。
- 后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。
示例
<div class="container container2">
<div class="inline-block">#divA inline-block</div>
<div class="float"> #divB float:left</div>
</div>
<div class="container container2">
<div class="inline-block" style="opacity: 0.9;">#divA inline-block</div>
<div class="float" style="opacity: 0.9;"> #divB float:left</div>
</div>.container{
position:relative;
background:#ddd;
margin-top:10px;
}
.container > div{
width:200px;
height:200px;
line-height:200px;
color:#333;
text-align:center;
font-size:18px;
font-weight:bold;
border:1px dashed #e6e6e6;
}
.float{
float:left;
background-color:deeppink;
}
.inline-block{
display:inline-block;
background-color:yellowgreen;
margin-left:-100px;
}显示效果:
上方的 div 是因为 inline-block 的层叠顺序在 float 上,下方的 div 因为 opacity 的设置,导致两个子 div 形成了 层叠上下文,然后二者的层叠水平一致时 DOM 流后面的元素会覆盖前面的