层叠上下文与z-index

35次阅读

z-index 是咱们之前相对比较常用的一个语法了,看起来比较简单的样子,实际上还真不难,因为这东西跟之前讲的 vertical-align 不一样,这个比较符合咱们的认知。
好了,不废话,开始咱们的正式话题。
首先呢?咱们先要了解一下层叠上下文(stack context)是什么呢,其实通俗来讲,就是你看电脑的这个方向的一个显示顺序,比如说,桌子上有一大堆纸,你对着它看的话,每一张纸,实际上你就可以理解为一个层叠上下文中的一个层叠顺序(stack level),你能看到的,往往是最靠前的那几张纸,后面的都被遮挡住了。
那么,首先最简单的一点。如果有有一摞的完全重合的值,你能看到的,往往都是最靠上的那张纸,也就是离你眼睛最近的那一张。然而对于咱们的 z -index 来说呢,值越大,也就相当于离你眼睛越近。在纸张里的位置越靠上。所以说,下面的代码,你应该一看就能知道,哪个元素在哪个元素的前面。
.paper1 {
position: absolute;
background-color: orange;
z-index: 2;
width: 100px;
height: 100px;
}
.paper2 {
position: absolute;
background-color: gray;
z-index: 5;
width: 50px;
height: 50px;
}

<div class=”paper1″></div>
<div class=”paper2″></div>

下面是结果图,我想聪明如你,一定都猜到了。

那么一个问题又来了,z-index 大的,一定会遮盖住 z -index 小的吗?不废话,直接看下面的代码。
.paper1 {
position: absolute;
width: 100px;
height: 100px;
background: orange;
z-index: 3;
}
.paper2 {
position: absolute;
width: 200px;
height: 200px;
background-color: aqua;
z-index: 2;
}
.paper3 {
position: absolute;
top: 80px;
width: 50px;
height: 50px;
background-color: red;
z-index: 4;
}

<div class=”paper1″></div>
<div class=”paper2″>
<div class=”paper3″></div>
</div>

你觉得哪个的层级最高呢?来看一下最终运行的结果把。

竟然不是.paper3 在最上面,他似乎被.paper1 给挡住了,按理来说,不是 z -index 越大的,层级越高吗?出现这种情况到底是为什么呢?
实际上,当 z -index 不为 auto 的时候,会自动创建一个它自己的层级上下文,也就是说,paper1 和 paper2 是同级的,他们都在根环境上下文上。但是 paper3 呢,是在 paper2 的环境上下文中,因为 paper1 的层级要比 paper2 要高,所以 paper3 的 z -index 哪怕再大,实际上也依然会被 paper1 给挡住的。
那么,问题又来了,只有 z -index 不为 auto 时才会创建环境上下文吗?答案肯定是否定的,实际上,咱们平时用到的不少 css 属性,也会自动创建环境上下文,下面咱们就看下 mdn 对这一块所列出来的一些属性(本文更新自 2019.3.25,如果看到此文时已经过了好几个月,甚至是一两年,推荐看英 mdn 页面:https://developer.mozilla.org…)。
层级上下文创建条件:

文档根元素 <html>.
position 值为 absolute 或者是 relative,并且 z -index 值不为 auto.
position 的值为 fixed 或者是 sticky(适用于所有的移动端浏览器,但是老旧的电脑端浏览器并不支持)

flex 容器的子元素,其 z -index 值不为 auto;
opacity 的值小于 1

mix-blend-mode 的属性值不为 normal
下面属性的值不为 none 时:        transform
        filter

         perspective、
        clip-path
         mask / mask-image / mask-border

isolation 的值为 isolate
-webkit-overflow-scrolling 的值为 touch 时
will-change
contain 的值为 layout, paint 或者是一个包含他们中任意一个的组合值(比如 contain: strict, contain:content)

看了上面的列表,应该会明白为什么我用 z -index 的时候,都会加 position: absolute 了吧。
那么,如果 z -index 值相同时,会怎么显示呢?实际上,他会按照先后顺序,后面的会覆盖前面的。如下面的例子:
.paper1 {
position: absolute;
width: 100px;
height: 100px;
background: orange;
z-index: 2;
}
.paper2 {
position: absolute;
width: 200px;
height: 200px;
background-color: aqua;
z-index: 2;
}

<div class=”paper2″></div>
<div class=”paper1″></div>

结果图如下:
那么如果此时吧两个 div 调换一下位置呢?那么就会如下图所示这样。

黄色的小块已经完全被蓝色的给挡住了。不过如果是下面的代码形式呢?
.paper1 {
display: inline-block;
width: 100px;
height: 100px;
background: orange;
}
.paper2 {
position: absolute;
width: 200px;
height: 200px;
background-color: aqua;
top: 0;
}

<div class=”paper1″></div>
<div class=”paper2″></div>

此时的话,小黄块将会被遮挡住,无论 paper1 在 paper2 的前面和后面,最后的结果都依然是一样的。如下图所示

但是呢,假如给.paper1 加入一个 transform:scale(1) 的话,他就会显示出来,依然会按照先后顺序,后面的先展示。
那么,为什么会这样呢?
首先呢?在一个层叠上下文中,实际上里面不同的元素是有不同的层叠顺序的,实际上下图已经很好的说明了这一点,其从下往上依次为
background/border-> 负 z -index->block 块状水平盒子 ->float 浮动元素 ->inline 水平盒子 ->z-index:auto 或者是 z -index: 0-> 正 z -index。
这个和咱们平时开发的表现是一致的。但是请注意 z -index:auto 和 z -index: 0; 的层级。他实际上是在 inline 水平元素的上面,因为定位元素,以及上面所列出来的 css3 的标签,很多都是默认的 z -index: auto; 所以上上个例子中,绝对定位的元素,始终会覆盖其 inline-block 元素。但是呢,其 inline-block 元素由于新加了 transform: scale(1) 以后呢,实际上会默认一个 z -index: auto; 所以他们俩实际上层级就一致了,因此他们也就是遵循后来居上的一个规则。谁在后面,谁就在靠上的位置。
同理,如果两个元素分别为 z -index: 0 和 z -index: auto; 的话,他们俩也遵循后来居上的规则,他们俩唯一的区别,就是 z -index: 0 会新建一个层叠上下文,而 z -index: auto; 则不会;
另外,许多 css3 属性中,比如说虽然 transform 默认是 z -index: auto,但是其实际上也会新建层叠上下文,所以,这块的话,你自己理解为有上面列出来的 css3 属性时,默认附带了一个 z -index: 0 就可以了。
当然了,我再写一个关于负 z -index 的例子,作为大家的一个小练习。不过我相信有了上面的铺垫后,这个对于大家来说,应该就没有很大的问题了
.paper1 {
display: inline-block;
width: 100px;
height: 100px;
background: orange;
}
.paper2 {
position: absolute;
width: 50px;
height: 50px;
background-color: aqua;
top: 0;
z-index: -1;
}
<div class=”paper1″>
<div class=”paper2″></div>
</div>

此时结果如下图

此时的话呢,由于 paper2 的 z -index 为 -1,由于 paper1 和 paper2 都在一个层叠上下文内(root),因此呢,paper2 就自然的在 paper1 下面。也就如上图所示。
但是如果给.paper1 增加了一个 tranform: scale(1) 呢,情况就会变得不太一样,如下图所示:

实际上就是因为增加了 transform: scale(1) 以后,实际上在 paper1 里面新建了一个层叠上下文,所以由于 paper2 是在 paper1 的层叠上下文里,所以它自然就显示出来了。无论其 z -index 值有多小。
好了,上面讲的也差不多了,不过依然是为了方便大家的理解,在最后,我简单的说一下其原理吧。
首先呢,其渲染树是一个深度优先的树结构,然后呢,先渲染的实际上会比后渲染的层级要更高一些,这个就跟咱们用不同的涂料刷墙一样,后刷的颜色总是会覆盖先刷的那些颜色,实际上网站渲染也是类似的。同时呢,在同级的时候,后面的要比前面的层级更高,实际上也是由于其遍历方式决定的,这个我就不多说了。
好了,完事了,谢谢大家观看,有什么问题想探讨的,或者我有什么错误遗漏的地方,都欢迎留言给我,谢谢大家
觉得不错的话,可以关注微信公众号:干活技术,每周都有一篇前端相关原创干货小文章分享
推荐阅读:
https://developers.google.com…
https://www.w3.org/TR/css-pos…
张鑫旭《CSS 世界》中 z -index 一章
本文转载自:http://www.lht.ren/article/21/

正文完
 0