学习笔记:CSS 世界的层叠规则

260 阅读6分钟

本文是阅读张鑫旭老师《CSS 世界》这本书的学习笔记。《CSS 世界》花了一章的篇幅,介绍网页元素的层叠规则。我看过两遍了,但还是记不住。于是又看了一遍,记了这个笔记,用我自己的话表述了一下。文中还附有我写的 demo 链接,贴在这里,跟大家分享。

Photo by Henry Lim on Unsplash

平时开发里会用到 z-index 属性,用来提升元素在页面中的层级,不被其他元素覆盖。举一些场景的例子:比如吸顶导航、自定义下拉框、自定义 tooltip、侧边悬浮对话框啥的。

z-index 的适应范围

z-index 的值是个整数,可以是正数,也可以是个负数,值越大,层级越高。但 z-index 是有使用范围的,它只在定位元素和 Flex 项目上使用才有效。

  1. 所谓“定位元素”就是 position 值不为 static 的元素。
  2. Flex 项目是对 Flex 容器(即 display 值为 flexinline-flex )直接子元素的称谓。

层叠顺序

z-index 的默认值是 auto,层叠效果等同于 z-index: 0。它的层叠水平是介于正数与负数之间的。

类似下面这样:

image.png

demo 地址:codepen.io/zhangbao/pe…

可以看见普通元素的层级是夹在 负 z-indexz-index: 0 之间的。普通元素按照层叠从小到大的顺序可以再细分为:块状元素、浮动元素和 inline 水平盒子。

因此,我们可以得到如下更加细节的顺序图:

image.png

demo 地址:codepen.io/zhangbao/pe…

可见,块状元素、浮动元素和 inline 水平盒子的层叠水平是依次增加的。

注意,这里的“inline 水平盒子”是指 inline/inline-block/inlint-table 元素。

从中我们也能看到,层叠水平不是仅仅适用于使用了 z-index 值的定位元素/Flex 项目,普通元素也具备层叠水平——即,所有元素都具有层叠水平。只不过应为用惯了 z-index 属性控制元素层级,感觉元素的层叠水平,只跟 z-index 属性有关系一样,这是不对的。

层叠规则

上面讲的是不同层叠水平元素的层叠顺序。那么,如果元素的层叠水平是一致的,那么又遵循什么规则呢?

有两个规则:

  1. 后来居上
  2. 谁大谁上

先讲 后来居上。举个例子:

<div style="display: flex;">
  <div>Flex 项目 1</div>
  <div>Flex 项目 2</div>
</div>

效果:

image.png

demo 地址:codepen.io/zhangbao/pe…

我们已经知道 Flex 项目的 z-index 默认值是 auto,层叠效果等同于 z-index: 0。因为现在 DOM 结构上靠后,因此比第一个 Flex 项目的层级要高。

再讲 谁大谁上

前面的 层叠顺序图 其实已经在表达这个意思了,但还不够明显。还是以上面 demo 为例,我们显式指定两个 Flex 项目的 z-index 值,就能看出区别了。

<div style="display: flex;">
  <div style="z-index: 1;">Flex 项目 1</div>
  <div style="z-index: 0;">Flex 项目 2</div>
</div>

image.png

10 大,所以第一个 Flex 项目在第二个的上面了。

z-index 并不能使元素上天入地无所不能,因为它还要受到 层叠上下文 这个“结界”的限制。

什么是层叠上下文?

层叠上下文可理解为一个“结界”,自成一个小世界。这个小世界中,可能存在其它的“结界”,而自身也可能处于其他“结界”之中。

可以通过以下方式创建一个层叠上下文:

  1. 页面根元素 <html>。成为根层叠上下文。
  2. z-index 值为数值的定位元素(这里有个特例:在 Chrome、Safair 等 Webkit 内核的浏览器,position: fixed 元素天然是层叠上下文元素,无需 z-index 为数值)。
  3. Flex 项目(父元素 display: flex|inline-flex),同时 z-index 值不是 auto
  4. 元素的 opacity 值不是 none,并且要小于 1
  5. 元素的 transform 值不是 none
  6. 元素的 mix-blend-mode 值不是 normal
  7. 元素的 filter 值不是 none
  8. 元素的 isolation 值是 isolate
  9. 元素的 will-change 属性值是上面 4~8 中的任意一个(比如 will-change: opacitywill-change: transform)。
  10. 元素的 -webkit-overflow-scrolling 设为 touch

其中,从第 4~10 项的元素称为“不依赖 z-index 的层叠上下文”,这些元素天然是 z-index: auto 级别。因此,我们的层叠顺序图,可以进一步补充为:

image.png

这里添加了一个“不依赖 z-index 的层叠上下文”,与之前的“z-index: auto 或看成 z-index: 0”(适应于定位元素和 Flex 项目)在同一个层叠水平。

demo 地址:codepen.io/zhangbao/pe…

我们通过里两个小例子,来说明层叠上下文的“结界”作用。

两个小例子

例子一:

<div class="p" style="position: relative; z-index: auto;">
	<div class="c" style="z-index: 2;">z-index: 2</div>
</div>

<div class="p" style="position: relative;z-index: auto;">
	<div class="c" style="z-index: 1;">z-index: 1</div>
</div>

效果:

image.png

通过上面对层叠上下文的定义,我们知道 z-index: auto;position: relative 元素不是层叠上下文。根据  谁大谁上 的层叠规则,z-index: 2 在 z-index: 1 之上。

我们稍微修改下代码:

<div class="p" style="position: relative; z-index: 0;">
	<div class="c" class="box" style="z-index: 2;">z-index: 2</div>
</div>

<div class="p" style="position: relative;z-index: 0;">
	<div class="c" class="box" style="z-index: 1;">z-index: 1</div>
</div>

效果:

image.png

demo 地址:codepen.io/zhangbao/pe…

根据定义,z-index 值为数值的定位元素具有层叠上下文。就是说,这个案例里的层叠规则,不是简单的比较两个 .c 的 z-index 值了,因为引入了层叠上下文,那么 .c 的层叠关系就是取决于父元素 .p 之间的关系了。

层叠上下文元素天然就是 z-index: auto 级别的,对于同层叠水平的两个 .p,根据 后来居上 的层叠规则,后一个 .p 的层级更高, 因此最终的表现是:z-index: 2 只能屈居于 z-index: 1 之下了。

层叠顺序(完整版)

既然层叠上下文是个“结界”,那么无论层叠上下文中所有后代元素的层叠顺序如何,都不会超出这个“结界”。

现在可以告诉大家的是,这个结界的“底儿”就是它的 backgroundborder。请看下面的图:

image.png

demo 地址:codepen.io/zhangbao/pe…

这就是完整版的层叠顺序图,层叠上下文的 backgroundborder 是整个顺序图的最底层。

以上 CSS 世界的层叠规则的所有内容啦!

(正文完)


广告时间(长期有效)

我有一位好朋友开了一间猫舍,在此帮她宣传一下。现在猫舍里养的都是布偶猫。如果你也是个爱猫人士并且有需要的话,不妨扫一扫她的【闲鱼】二维码。不买也不要紧,看看也行。

(完)