层叠上下文
什么是层叠上下文
-
层叠上下文(stacking context),是 HTML 中一个三维的概念,在 CSS2.1 规范中,每个盒模型的位置是三维的,分别是平面画布上的 X 轴、Y 轴以及表示层叠的 Z 轴;
-
一般情况下,元素在页面上沿 X 轴 Y 轴平铺,察觉不到它们在 Z 轴上的层叠关系;
-
一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖;
创建层叠上下文
-
第一种方式:HTML 中的根元素 HTML 本身就具有层叠上下文,称为 根层叠上下文;
-
第二种方式:普通元素设置 position 属性为非 static 值并设置 z-index 属性为具体数值,会产生层叠上下文;
-
第三种方式:CSS3 中的新属性也可以产生层叠上下文;
层叠等级与层叠顺序
-
除了层叠上下文,还需要了解两个概念:
- 层叠等级( stacking level )
- 层叠顺序( stacking order )
-
这两个东西实际上都是用来表述:在同一个层叠上下文中,元素在 z 轴上的显示顺序 ,只不过前一个是概念,后一个是具体规则;
-
如果两个元素在同一个层叠上下文中,那么层叠等级越大的元素,就越靠前;
- 那么问题来了,我怎么知道该元素的层叠等级是高还是低?
- 所以层叠等级的高低规则是由层叠顺序来体现的;
- 在 CSS2.1 的年代(注意这里的前提),层叠顺序规则遵循下面这张图:
-
那么如果两个元素不在同一个层叠下上文中呢?那么此时就先比较他们所处的层叠上下文的层叠等级,也就是所谓的 从父 现象,比较他们的父元素即可;
实战案例
首先先看要比较的两个元素是否处于同一个层叠上下文中:
- 如果是,谁的层叠等级大,谁在上面(判断层叠等级大小参阅上面的 层叠顺序 图);
- 如果两个元素不在同一层叠上下文中,请先比较他们所处的层叠上下文的层叠等级;
当两个元素层叠等级相同、层叠顺序相同时,在 DOM 结构中后面的元素层叠等级在前面元素之上;
示例 1
one 和 two 分别有自己的层叠上下文,但是 two 的层叠等级要比 one 高;
之后可以看到,无论 one 中的子元素的 z-index 设置有多高,它始终被 two 的子元素给覆盖,因为如果两个元素不在同一层叠上下文中,比较的是所在层叠上下文的等级;
<style>
.tmp1-box {
width: 200px;
height: 200px;
}
.tmp1-one {
background-color: red;
position: relative;
z-index: 1;
}
.tmp1-two {
background-color: blue;
position: relative;
z-index: 2;
}
.tmp1-item {
width: 100px;
height: 100px;
position: absolute;
left: 200px;
top: 200px;
}
</style>
<div class="tmp1-box tmp1-one">
<div class="tmp1-box tmp1-item" style="background-color: black; z-index: 99;"></div>
</div>
<div class="tmp1-box tmp1-two">
<div class="tmp1-box tmp1-item" style="background-color: pink;top: 50px; z-index: 1;"></div>
</div>
示例 2
.box1 和 .box2 虽然设置了 position: relative,但是没有设置 z-index ,所以 .box1 和 .box2 仍然是普通元素;
所以 .child1 和 .child2 属于 html 元素的 根层叠上下文 中,也就是处于同一个层叠上下文中,根据层叠顺序谁的 z-index 值大,谁在上面;
<style>
.tmp2-box1,
.tmp2-box2 {
position: relative;
}
.tmp2-child1 {
width: 200px;
height: 100px;
background: #168bf5;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.tmp2-child2 {
width: 100px;
height: 200px;
background: #32c292;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
</style>
<div class="tmp2-box1">
<div class="tmp2-child1"></div>
</div>
<div class="tmp2-box2">
<div class="tmp2-child2"></div>
</div>
示例 3
将上面案例中的 CSS 代码稍作修改,仅仅修改了 .box1 和 .box2 的 z-index 属性值改为数值 0 ,最终结果完全相反;这时 .child2 覆盖在了 .child1 上面;
设置 z-index: 0 后,.box1 和 .box2 产生了各自的层叠上下文,这时候要比较 .child1 和 .child2 的层叠关系属于不同的层叠上下文进行比较;此时由由各自所在的 .box1 和 .box2 的层叠等级来决定;
但是 .box1 和 .box2 的 z-index 值都为 0 ,都是块级元素(所以它们的层叠等级,层叠顺序是相同的),这种情况下,在 DOM 结构中后面的覆盖前面的,所以 .child2 就在上面;
<style>
.tmp2-box1,
.tmp2-box2 {
position: relative;
z-index: 0;
}
.tmp2-child1 {
width: 200px;
height: 100px;
background: #168bf5;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.tmp2-child2 {
width: 100px;
height: 200px;
background: #32c292;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
</style>
<div class="tmp2-box1">
<div class="tmp2-child1"></div>
</div>
<div class="tmp2-box2">
<div class="tmp2-child2"></div>
</div>
示例 4
.tm4-box 虽然设置了定位,但是并没有设置 z-index 属性,所以并不会产生层叠上下文,仅仅是一个普通元素;
此时 .tm4-item 图片属于 html 元素的 根层叠上下文 中,根据层叠顺序谁的 z-index 值大,谁在上面
<style>
.box{
width: 200px;
height: 200px;
background: blue;
position: absolute;
}
.item{
position: absolute;
width: 200px;
left: 50px;
top: 50px;
z-index: -1;
}
</style>
<div class="box">
<img src="/article/5a16e3ca/meimei.png" alt="" class="item">
</div>
示例 5
将上面的代码稍作修改,为 .tmp5-box 添加一个 z-index 属性,并且给了一个很大的值;
当 .tmp5-box 设置了 z-index 后,就会产生一个层叠上下文,也就是说对 .tmp5-item 图片而言,找到的层叠上下文是 .tmp5-box 而不是 html 根元素;而根据层叠顺序,background 是处于最下层的,所以图片显示在了最上面;
<style>
.tmp5-box{
width: 200px;
height: 200px;
background: blue;
position: absolute;
z-index: 99;
}
.tmp5-item{
position: absolute;
width: 200px;
left: 50px;
top: 50px;
z-index: -1;
}
</style>
<div class="tmp5-box">
<img src="/article/5a16e3ca/meimei.png" alt="" class="tmp5-item">
</div>
示例 6
对于 .tmp6-child1 和 .tmp6-child2 来讲,他俩是处于同一个层叠上下文中,所以 .tmp6-child1 在 .tmp6-child2 的上面(因为 .tmp6-child1 的 z-index 值更大);
而对于 .tmp6-child2-1 和 .tmp6-child2-2 来讲,他俩也是处于同一个层叠上下文 .tmp6-child2 里面,所以无论 .tmp6-child2 的 z-index 值有多大,都一定在 .tmp6-child2-1 和 .tmp6-child2-2 下面;而 .tmp6-child2-1 和 .tmp6-child2-2 则根据 z-index 值的大小来决定谁覆盖谁;
<style>
.tmp6-parent {
width: 100px;
height: 200px;
background: #168bf5;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.tmp6-child1 {
width: 100px;
height: 200px;
background: #32d19c;
position: absolute;
top: 20px;
left: 20px;
z-index: 1;
}
.tmp6-child2 {
width: 100px;
height: 200px;
background: #e4c950;
position: absolute;
top: 40px;
left: 40px;
z-index: -1;
}
.tmp6-child2-1 {
width: 100px;
height: 200px;
background: #e45050;
position: absolute;
top: 60px;
left: 60px;
z-index: 9999;
}
.tmp6-child2-2 {
width: 100px;
height: 200px;
background: #db68a7;
position: absolute;
top: 80px;
left: 40px;
z-index: -9999;
}
</style>
<div class="tmp6-parent">
parent
<div class="tmp6-child1">child1</div>
<div class="tmp6-child2">
child2
<div class="tmp6-child2-1">child2-1</div>
<div class="tmp6-child2-2">child2-2</div>
</div>
</div>
CSS3 中属性对层叠上下文的影响
-
CSS3 中出现了很多新属性,其中一些属性对层叠上下文也产生了很大的影响,如下:
- 父元素的 display 属性值为 flex | inline-flex,子元素 z-index 属性值不为 auto 的时候,子元素为层叠上下文元素;
- 元素的 opacity 属性值不是 1;
- 元素的 transform 属性值不是 none;
- 元素 mix-blend-mode 属性值不是 normal;
- 元素的 filter 属性值不是 none;
- 元素的 isolation 属性值是 isolate;
- will-change 指定的属性值为上面任意一个;
- 元素的 -webkit-overflow-scrolling 属性值设置为 touch;
-
CSS3 中,元素属性满足以上条件之一,就会产生层叠上下文;用第 1 条来做一个简单的解释说明;
- 当给 .css3-box 设置 display: flex 时,.css3-parent 也会变成一个弹性项目,成为一个层叠上下文元素。于是对于 .css3-child 来讲找到的层叠上下文就是 .css3-parent 了,而非 html 根元素;
- 根据层叠顺序规则,层叠上下文元素的 background/border 的层叠等级小于 z-index 值小于 0 的元素的层叠等级,所以 z-index 值为 -1 的 .css3-child 在 .css3-parent 上面;
<style> .css3-box { display: flex; } .css3-parent { width: 200px; height: 100px; background: #168bf5; /* 虽然设置了z-index,但是没有设置position,z-index 无效,.parent还是普通元素,没有产生层叠上下文 */ z-index: 1; } .css3-child { width: 100px; height: 200px; background: #32d19c; position: relative; z-index: -1; } </style> <div class="css3-box"> <div class="css3-parent"> parent <div class="css3-child">child</div> </div> </div>
parentchild
真题解答
请简述什么是层叠上下文
在 CSS2.1 规范中,每个盒模型的位置是三维的,分别是平面画布上的 X 轴,Y 轴以及表示层叠的 Z 轴;
一般情况下,元素在页面上沿 X 轴 Y 轴平铺,察觉不到它们在 Z 轴上的层叠关系;而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖;
层叠上下文触发条件
- HTML 中的根元素 HTML 本身就具有层叠上下文,称为 根层叠上下文;
- 普通元素设置 position 属性为非 static 值并设置 z-index 属性为具体数值,产生层叠上下文;
- CSS3 中的新属性也可以产生层叠上下文;
什么是层叠等级
如果两个元素在同一个层叠上下文中,那么层叠等级越大的元素,就越靠前;
层叠等级是一个概念,层叠等级的大小可以根据层叠顺序来进行判断;
什么是层叠顺序
层叠顺序表示元素发生层叠时按照特定的顺序规则在 Z 轴上垂直显示;
说简单一点就是当元素处于同一层叠上下文内时如何进行层叠判断;
CSS 高级✍️ CSS 渲染性能优化
上一篇