[译] CSS 中 z-index 的工作原理解析

DaisyTammy 发布于2月前 •最后由 野人山2月前回复
2 条问题

原文地址: https://blog.logrocket.com/how-css-works-creating-layers-with-z-index-6a20afe1550e

原文作者: Benjamin Johnson

介绍

这篇文章是"How CSS workd"系列文章中的第三篇(深入探讨CSS基本构建模块的系列文章,这些基本构建模块有时会让人感觉像是黑魔法)。无论你如何编写你的css代码,知道样式表的运行原理总是极好的,这样你才能编写出高效的、可伸缩性css代码。

下面是系列文章中的前两篇:

  1. css如何工作 — 解析和绘制css的关键路径 :深入研究CSS引擎在浏览器请求css文件到用户实际在屏幕上看到的像素过程中发生了什么
  2. css如何工作 — 了解层叠 :讲解“css中的"c"以及层叠算法如何将各种css规则解析为浏览器中实际显示的样式

今天我们研究css的另一个黑魔法 — z-index,耍z-index,通常感觉像是往墙面上扔一个更高的数字,然后看看是什么效果。

但如果我们试着剥离z-index上的层,看看管理他们的规则呢,我们会发现它并不像我们想象的那么可怕。

究竟什么是z-indx?

说到底,我们在浏览器中使用的屏幕是一组由像素组成的二维平面,但如果你经常上网,你可能会经常体会到"三维”世界,例如,你可以单击一个按钮打开一个 modal,或者触发一个tool-tip

如果你假设用户正在看屏幕,并想象屏幕是三维世界的入口,你可以开启浏览器中的三维空间呈现,首先,我们把该空间想象成一个房间,那么"最远"的"墙"就被称为"画布 canvas"

当在屏幕是绘制像素时,浏览器首先会确保绘制距画布最近(或最远)�的像素,然后,他将渐进的将元素"更接近"用户,并覆盖以前绘制的像素

z-index属性表示元素在三维浏览器视觉中绘制的顺序,默认情况下,所有元素的 z-index 皆为0,浏览器按照 DOM 顺序进行绘制,然而实际上,z-index 为我们提供了何时绘制元素的细节控制,通过指定较高的 z-index,我们可以使绘制出的元素"更接近"用户,如果我们指定一个较低的(或负值)z-index,我们可以使绘制出的元素更接近画布。

在深入研究 CSS 的位置和布局规范时,我发现了这个有用的图片,它可以直观的显示出 z-index 层叠对用户视觉的影响。

[译] CSS 中 z-index 的工作原理解析

具有较高 z-index 的元素看起来"更接近"用户

如果我们只看到 z-index 的这种特性,我们很容易被诱导认为它就是 z-index 的全部知识了:更高的 z-index就更接近用户,更小的 z-index 则更远离,然而,z-index 还有一些细节常被混淆。

z-index 的第一个注意点是它必须在被设定了 position 属性元素上时才会生效,这意味着, z-index 只有在 position 设置为除 static 属性上的元素上时,它才能更改层叠顺序,在元素没有设置任何 position 的情况下,z-index 将不会起任何作用。

层叠上下文介绍

当我们探讨到 z-index 的第二个注意点时, z-index 变得更加让人困惑了,因为 z-index 只适用于层叠环境中的元素。

层叠上下文涉及到了 HTML 节点和它的所有子节点, HTML 元素位于层叠上下文的 root 级别,它可以被称为根层叠。

文档的默认层叠上下文(或"根层叠上下文")将 HTML 元素标记为其"根层叠",并且默认情况下,所有元素都属于此根层叠上下文,但是,任何元素节点也可以是其"局部层叠上下文"中的根层叠。

你可以通过以下几种方法将元素指定为新的局部层叠上下文的根层叠:

  1. 在设置了 position 为 absolute 或 relative 或其它任何除了 auto 属性上设置 z-index
  2. 使用 position: fixed 或 position: sticky
  3. 元素上设置的 opacity 属性值小于1
  4. 在元素上使用 transform 或 will-change

如果你想看到更多创建层叠环境的方法,请在 MDN上查看 该文章

作为例子,让我们想象 HTML 的三个树节点,将它们想想为三个层叠,在下图中,每个层叠的底部是 HTML 节点,子元素堆叠在其上(有点像 HTML 树的颠倒表示),让我们假设这些元素都是 body 标签的直接子节点。

[译] CSS 中 z-index 的工作原理解析

如果我们在浏览器中预览这些HTML元素,它将表示为如下:

注意到什么有趣的事情了吗?

首先,为什么 blue-child-1 低于其它标签?它的 z-index 是1000000,它不是应该在最上面吗?

此外,为什么 green-child-1 为什么显示在所有元素的顶部,及时它的 z-index 为2,我们不是说更高级别的z-index胜过更低级别的z-index吗?

让我们从 green-child-1 元素开始,因为它的父元素 green-parent 的z-index为999,我们期望 green-parent 元素也高于其它元素,但如果我们回想一下使用 z-index的第一个警告:它对静态定位的元素没有影响,这意味着 green-child-1 是层叠上下文的一部分,它是根据 red-parent 和 blue-parent (根层叠中唯一的其它两个元素)进行测量的,它的z-index比这两个更高,所有它显示在顶部。

了解 red-parent 和 blue-parent 各自创建的局部层叠环境也有助于我们了解为什么 blue-child-2 显示在 red-parent 之下,即使其 z-index 更高,由于 z-index 仅控制元素在其局部层叠上下文中的位置,因此 blue-child-2 肯定要高于 blue-parent 的子级。但是 red-parent 的 z-index 要高于 blue-parent ,无论它们的 z-index 是多少, red-parent 内部的所有元素都将比 blue-parent 元素显示出更高的 z-index

为了使 blue-child-2 显示在 red-parent 之上,我们实际上必须要更改HTML结构,使得 blue-hild-2 脱离它当前的局部层叠上下文环境,并使其进入根层叠上下文(或者至少是位于 red-parent 之上的层叠上下文)。

在大型web应用中,这样变更通常是很麻烦切危险的,特别是当你试图管理语义化的HTML结构或模块化组件结构时。

你经常看到许多组件库通过将元素添加到 body 标签中,而不是包含在你自己定义的组件中以此来实现更高曾经的UI 组件(如 tool-tips和modal),这么做可以在很大程度上避开这些层叠上限文"陷阱",这么做也可以确保严重依赖层叠的组件的z-index始终处于根层叠上下文环境中,因此它们可以将z-index设为值1000,并相信他将显示在大多数元素的顶部。

结论

在一些情况下,使用 z-index 可能很麻烦,但是当我们知道它的底层原理及工作规则时,我们会发现它的行为实际上是相当可预测的,我想99%的关于 z-index 的混淆都源自我们在上面讨论的那两个警告的误解

作为复习,我在这里再强调一遍:

  1. z-index 仅用于除 static 元素外的具有 position 的元素
  2. z-index 仅适用于元素在其所属的层叠上下文中的位置

我希望你以后在遇到多层 ui 导致的各种陷阱时,了解 z-index 的内部结构会给你带来信心,我知道,研究 z-index 和层叠系统对于我们更好的开发ui会更有帮助。

查看原文: [译] CSS 中 z-index 的工作原理解析

  • brownswan
  • goldenswan
  • orangefrog
  • blackduck
  • 野人山
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。