渲染过程和层叠顺序
浏览器将HTML解析为DOM的同时还创建了另一个树形结构,渲染树(render tree)。渲染树代表了每个元素的视觉样式和位置,同时决定浏览器绘制元素的顺序。
- 通常情况下(没有使用定位),元素在HTML里出现的顺序决定了绘制顺序。后绘制的元素会出现在先绘制的元素前面。
- 定位元素时,这种行为会改变。浏览器会先绘制所有非定位的元素,然后绘制定位元素。默认情况下,所有的定位元素会出现在非定位元素前面。
使用z-index控制层叠顺序
z-index
属性的值可以是任意整数(正负都行)。表示的是笛卡儿坐标系里的深度方向。拥有较高z-index
的元素出现在拥有较低z-index
的元素前面。拥有负数z-index
的元素出现在静态元素后面。
z-index
的行为很好理解,但是使用它时要注意两个小陷阱。
z-index
只在定位元素上生效,不能用它控制静态元素。- 给一个定位元素加上
z-index
可以创建层叠上下文。
层叠上下文
一个层叠上下文包含一个元素或者由浏览器一起绘制的一组元素。其中一个元素会作为层叠上下文的根,比如给一个定位元素加上z-index
的时候,它就变成了一个新的层叠上下文的根。所有后代元素就是这个层叠上下文的一部分。
所有层叠上下文内的元素会按照以下顺序,从后到前叠放:
- 层叠上下文的根
z-index
为负的定位元素(及其子元素)- 非定位元素
z-index
为auto
的定位元素(及其子元素)z-index
为正的定位元素(及其子元素)
举个例子
下面这个例子可以用来理解层叠上下文,nested在第一个盒子的层叠上下文中,就算设置了很高的z-index
,也会被第二个盒子遮挡。因为第一个盒子形成的层叠上下文在第二个盒子后面。
<body>
<div class="box one positioned">
one
<div class="absolute">nested</div>
</div>
<div class="box two positioned">two
</div>
</body>
body {
margin: 40px;
}
.box {
display: inline-block;
width: 200px;
line-height: 200px;
text-align: center;
border: 2px solid black;
background-color: #ea5;
margin-left: -60px;
vertical-align: top;
}
.one { margin-left: 0; }
.two { margin-top: 30px; }
.positioned { (以下5行)每个定位的盒子都创建了一个层叠上下文,z-index为1
position: relative;
background-color: #5ae;
z-index: 1;
}
.absolute {
position: absolute;
top: 1em;
right: 1em;
height: 2em;
background-color: #fff;
border: 2px dashed #888;
z-index: 100; ←---- z-index只控制元素在它所处层叠上下文内的层叠顺序
line-height: initial;
padding: 1em;
}
表现结果
扩展到实际应用中的场景是,在已经打开的弹窗中再打开一个弹窗,就算第一个弹窗中的某个元素设置了很高的z-index
,也还是会被第二个(后绘制)的弹窗挡住。