几个概念
-
层叠上下文
- 层叠上下文模型可看做CSS的三维盒子模型,有创建层叠上下文能力的元素可作为层叠容器存在,按照层叠顺序表存放其他层叠元素。
- 一个元素,在层叠上的容器,是它的第一个具有层叠上下文能力的祖先(一直向上找到第一个能容纳它的祖先)
- 具有创建层叠上下文能力的元素有:
- 根元素 (HTML标签),
- z-index 值不为 "auto"的 绝对/相对定位,
- 一个 z-index 值不为 "auto"的 flex 项目 (flex item),即:父元素 display: flexinline-flex,
- opacity 属性值小于 1 的元素(参考 the specification for opacity),
- transform 属性值不为 "none"的元素,
- mix-blend-mode 属性值不为 "normal"的元素,(混合模式)
- filter值不为“none”的元素,
- perspective值不为“none”的元素,
- isolation 属性被设置为 "isolate"的元素,
- position: fixed的元素
- 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考 这篇文章)
- -webkit-overflow-scrolling 属性被设置 "touch"的元素
- 层叠顺序:在一个层叠上下文容器里,层叠上下文元素它自己和它的直接子层叠元素是安装下表渲染的:(越先提到越早渲染)
- 层叠上下文元素的背景
- 负z-index的元素(越小越早)
- block元素
- 具有float的元素
- inline/inline-block盒子
- z-index:auto / z-index:0 (等级一样,但z-index:auto原则上不创建层叠上下文)、非因z-index创建的层叠上下文元素
- 正z-index的元素(越大越晚)
- 如果遇到相同等级的,在dom流里先遇到的先渲染,即后来居上
- 层叠上下文元素它自己属于2-7的其中一个 一般属于2、6、7
实际的渲染的顺序
我们把一个 有创建层叠上下文能力的元素称之A 接下来讲一下怎么从A开始渲染 (最开始的A就是根元素HTML标签)
- 准备一个逻辑上的空数组。
- 把A放进数组。
- 取出A的所有后代。
- 对于数组里的每一个不具有创建层叠上下文能力的元素,取出它的所有后代。
- 重复4到数组不再变化。到这一步,A的所有直接子后代还有它自己,都在数组里了。这些元素都依托A为舞台来渲染。
- 然后把数组里的元素,按照层叠顺序渲染。
- 去掉数组里所有不具有创建层叠上下文能力的元素。
- 对于数组里所有具备创建层叠上下文能力的元素,它们的子孙将依托它们为舞台来渲染,因此对他们中的每一个重复1-8。
于是乎,最终渲染的效果特点:
- 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文。
- 每个层叠上下文和兄弟层叠上下文独立,也就是当进行层叠渲染的时候,每个层叠上下文元素只需要考虑自己盒子里的。
- 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。(类比大版本号、爹说了算)
demo
demo1:爹的地位说了算
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
* {
margin: 0;
}
html {
padding: 20px;
font: 12px/20px Arial, sans-serif;
}
div {
opacity: 0.7;
position: relative;
}
h1 {
font: inherit;
font-weight: bold;
}
#div1,
#div2 {
border: 1px dashed #696;
padding: 10px;
background-color: #cfc;
}
#div1 {
z-index: 5;
margin-bottom: 190px;
}
#div2 {
z-index: 2;
}
#div3 {
z-index: 4;
opacity: 1;
position: absolute;
top: 40px;
left: 180px;
width: 330px;
border: 1px dashed #900;
background-color: #fdd;
padding: 40px 20px 20px;
}
#div4,
#div5 {
border: 1px dashed #996;
background-color: #ffc;
}
#div4 {
z-index: 6;
margin-bottom: 15px;
padding: 25px 10px 5px;
}
#div5 {
z-index: 1;
margin-top: 15px;
padding: 5px 10px;
}
#div6 {
z-index: 3;
position: absolute;
top: 20px;
left: 180px;
width: 150px;
height: 125px;
border: 1px dashed #009;
padding-top: 125px;
background-color: #ddf;
text-align: center;
}
</style>
</head>
<body>
<div id="div1">
<h1>Division Element #1</h1>
<code>
position: relative;<br/>
z-index: 5;
</code>
</div>
<div id="div2">
<h1>Division Element #2</h1>
<code>
position: relative;<br/>
z-index: 2;
</code>
</div>
<div id="div3">
<div id="div4">
<h1>Division Element #4</h1>
<code>
position: relative;<br/>
z-index: 6;
</code>
</div>
<h1>Division Element #3</h1>
<code>
position: absolute;<br/>
z-index: 4;
</code>
<div id="div5">
<h1>Division Element #5</h1>
<code>
position: relative;<br/>
z-index: 1;
</code>
</div>
<div id="div6">
<h1>Division Element #6</h1>
<code>
position: absolute;<br/>
z-index: 3;
</code>
</div>
</div>
</body>
</html>
demo2:父级层叠上下文(层叠意义上的容器)是自下往上具有创建上下文能力的第一个祖先
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
body {
position: absolute;
}
.div1 , .div3 {
width: 100px;
height: 100px;
margin-left: 100px;
margin-top: 50px;
background-color: yellow;
}
.div2 , .div4 {
position: relative;
width: 50px;
height: 50px;
margin-left: -40px;
background-color: red;
z-index: -1;
}
.div3 {
position: relative;
z-index: 0;
}
</style>
</head>
<body>
<div class="div1">
div1
<div class="div2">
div2
</div>
</div>
<!-- div1没有创建层叠上下文的能力,所以div1和div2在层叠层级上,都是body的直接子元素,所以div2会在下面,渲染在body的背景上方,在block元素div1下方 -->
<div class="div3">
div3
<div class="div4">
div4
</div>
</div>
<!-- div3有创建层叠上下文的能力,所以div2在层叠层级上,是div3的子元素,因此会渲染在div3的背景上方 -->
</body>
</html>