25

CSS 的“层”峦“叠”翠 - 一文掌握z-index用法​​​​​​​

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzA5NzkwNDk3MQ%3D%3D&%3Bmid=2650591375&%3Bidx=1&%3Bsn=f26a6e00244ae071370701cc6944b33c
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

~欢迎点击上方 蓝字 歪码行空 快速关注~

前言

提起, z-index 大家脑海里可能会立刻浮现这样的知识点:“ z-index 的值大小控制元素在 Z 轴上显示的层级, z-index 越大显示的层级越高(也就是在最上层,离观察者越近),没有指定的按照出现顺序堆叠,此外 z-index 不能跨父元素比较。

z-index 的使用似乎就是这么简单,对吧?

我们先看如下例 1:

<div class="box box1">DIV#1,z-index为2</div>
  <div class="box box2">DIV#2,z-index为auto</div>

HTML 中有如下两个元素,DIV#1 的 z-index2 ,DIV#2 向右向上偏移。问:它们谁会显示在上面?

nyyYrem.png!web 示例1 - 用法引导

点击 CSS 的“层”峦“叠”翠 - 示例 1 - 用法导引 [1] 查看示例

如上所示, z-index 为 2 的元素并没有显示在第二个元素上面。这似乎很奇怪,那到底是为什么呢?

如果你也对此存在困扰,那就和我一起往下看吧。笔者将逐步引导大家深入理解 z-index 的用法。

一、没有使用 z-index 时,元素如何堆叠?

首先,我们先了解下默认情况下,元素的堆叠,即在没有使用 z-index 时,元素是如何堆叠的。

如果没有给任何元素指定 z-index,则元素按照如下顺序进行堆叠(由下到上,由远及近)。

  1. 根元素的背景和边框

  2. 非定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

  3. 定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

注:定位的元素即为 position 的值不是 static 的元素

EfmAZvI.jpg!web 示例2 - 无z-index时的默认堆叠

点击 CSS 的“层”峦“叠”翠 - 示例 2 - 无 z-index 时的默认堆叠 [2] 查看示例

如上例 2 所示,定位的元素(DIV#1、DIV#2、DIV#3 与 DIV#4)按照出现的顺序堆叠。非定位的元素(DIV#5 与 DIV#6)虽然出现在后面,但是会被定位的元素遮盖,不过它们本身是按照出现顺序堆叠的。

注意,当使用order属性改变flex元素子元素的出现顺序时,对于堆叠规则也有同样的影响。

如下例 3 所示,当将 DIV#2 的 order 改为-1 后,它出现的位置为第一个,其堆叠顺序也被 DIV#1 所遮盖。

FJnmEv6.png!web 示例3 - flex中order对出现顺序的影响

点击 CSS 的“层”峦“叠”翠 - 示例 3 - flex 中 order 对出现顺序的影响 [3] 查看示例

二、浮动块默认如何堆叠

如果存在浮动块,浮动块的堆叠顺序会介于无定位元素和定位元素之间。即:

  1. 根元素的背景和边框

  2. 非定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

  3. 浮动块

  4. 定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

我们稍微修改下示例 2 中的代码,将 DIV#1 和 DIV#3 改为浮动元素。可以看到如下例 4 所示,浮动元素的堆叠顺序高于非定位元素,低于定位元素。

fEZnIrU.jpg!web 示例4 - 浮动块的堆叠

点击 CSS 的“层”峦“叠”翠 - 示例 4 - 浮动块的堆叠 [4] 查看示例

此外,还有一点小改动,不知道你有没有注意到,我们将非定位元素中的文本内容改为了左对齐,但其内容并没有被浮动元素覆盖。这其实是浮动元素的标准效果——环绕效果。这一行为也可以列为堆叠顺序之一。顺序如下:

  1. 根元素的背景和边框

  2. 非定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

  3. 浮动块

  4. 非定位元素的后代行内元素

  5. 定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

为了让大家清晰的理解上面所说的非定位元素的后代行内元素。大家可以看下例 5。DIV#1 为浮动元素,所以其层级高于在其后出现的 DIV#2。此时 DIV#1 向右偏移,可以看见 DIV#2 中的行内文字元素(可以为纯文字节点)层级高于 DIV#1。

Evy6n2B.png!web 示例5 - 非定位元素的后代行内元素

点击 CSS 的“层”峦“叠”翠 - 示例 5 - 非定位元素的后代行内元素 [5] 查看示例

三、使用 z-index 自定义堆叠顺序

以上是 CSS 中对于各类元素的默认排序,那我们能否自定义排序呢?答案显然是肯定的。使用 z-index 可以自定义堆叠顺序。

z-index 的值可以为整数(正数、负数、0 均可)。使用方法很简单。

需要注意以下三点:

  1. 未指定 z-index ,默认为 auto
  2. 如果 z-index 相同,则按照默认规则比较
  3. z-index 只能用于定位了的元素 (暂时这么说,下文会追加解释)。 这也解释了本文开头的例 1 为什么不生效了。因为 z-index 对普通元素没有效果。

如下例 6,我们修改了例 2 中元素的 z-index。

我们会发现 DIV#5 和 DIV#6 并不受 z-index 的影响 。主要体现在两个方面,首先 DIV#5 的 z-index 大于 DIV#6,但是显示却低于 DIV#6;其次是 DIV#5 的 z-index 小于 DIV#4,但是仍显示在其上面。

而对于定位的元素,z-index 对其有影响,堆叠顺序与数字大小符合。

IRJb2af.jpg!web 示例6 - 使用z-index自定义堆叠顺序

点击 CSS 的“层”峦“叠”翠 - 示例 6 - 使用 z-index 自定义堆叠顺序 [6] 查看示例

好了,相信通过上述内容,大家对于 z-index 应该有了一定的了解,但是以上仅仅是基本知识,关于堆叠远远没有这么简单。

想要彻底了解 z-index,我们还要了解一下 CSS 堆叠的一个重要概念————堆叠上下文。

四、堆叠上下文

堆叠上下文是 HTML 中的三维概念,它抽象出了一个 z 轴,z 轴垂直于显示器,指向用户(假设用户面朝显示区域)。

在前面的内容中,之所以有些元素的渲染顺序会受到 z-index 影响,是因为它们都因为某种原因产生了一个 堆叠上下文 ,而不仅仅是上文提到的定位的元素。

那么到底什么情况下会产生堆叠上下文呢?其实堆叠上下文的生成主要受到元素的属性所影响。

如果任何一个元素满足以下条件之一,就会生成一个堆叠上下文。

  1. 文档的根元素(HTML)默认为一个堆叠上下文

  2. position 值为"absolute"或"relative",且 z-index 指定了除了 auto 以外值的元素
  3. position 值为"fixed"或"sticky"
  4. 弹性布局的子元素,且 z-index 指定了除了 auto 以外值的元素
  5. opacity 的值小于1的元素
  6. mix-blend-mode 的值不是 normal 的元素
  7. 以下属性值不为"none"的元素

  • transform

  • filter

  • perspective

  • clip-path

  • mask / mask-image / mask-border

isolation 值为"isolate"的元素
-webkit-overflow-scrolling 值为"touch"的元素
will-change 指定了除初始值以外的任何属性的元素
contain 值为"layout"/"paint"及含义其中之一的组合值的元素

如上所述,有 11 种情况会生成堆叠上下文,对于堆叠上下文可以通过 z-index 指定其堆叠的顺序(注意这里不是上面说的只对定位元素生效了)。

对于堆叠上下文我们需要知道以下几点:

  1. 在每个堆叠上下文内部,子元素的堆叠规则遵循上面所讲的基本规则。

  2. 堆叠上下文可以包含在其他堆叠上下文内部,它们会创建一个堆叠上下文层级结构。

  3. 堆叠上下文的层级结构与 HTML 的元素不同,因为对于没有创建堆叠上下文的元素会被父元素同化。 堆叠上下文的层级只包括创建了堆叠上下文的元素

  4. 堆叠上下文独立于其兄弟元素,在处理自身内部堆叠时,只考虑其后代元素。内部堆叠完成后,将当前堆叠上下文当成一个整体,考虑在父堆叠上下文中的堆叠顺序。通俗的说, 子堆叠上下文的 z-index 值只在父堆叠上下文中有意义。

注意,第四条和文章开头提到的“z-index 不能跨父元素比较”是不等价的,因为其限制了必须是堆叠上下文。

针对这几点,我们看一下例 7。大家可以先看一下是否理解。然后我们再讲解一下。

EbeIjee.jpg!web 示例7 - 存在多级堆叠上下文时,元素的堆叠

点击 CSS 的“层”峦“叠”翠 - 示例 7 - 存在多级堆叠上下文时,元素的堆叠 [7] 查看示例

示例 7 中,堆叠上下文的层级结构如下:

  • root

    • DIV#4

    • DIV#5

    • DIV#6

    • DIV#1

    • DIV#2

    • DIV#3

    • DIV#8

其中 DIV#4, DIV#5, DIV#6 是 DIV#2 的子元素,可见其堆叠顺序被限制在 DIV#2 中, z-index 的值只在 DIV#2 内部有效,然后 DIV#2 又作为一个整体与 DIV#1,DIV#3 按照上述规则进行堆叠。

DIV#7 被根元素同化,DIV#8 与 DIV#1, DIV#2, DIV#3 按照上述规则进行堆叠。在其三之上。

其实有个小方法能够帮助大家更好地判断如何堆叠,那就是把堆叠上下文的层级结构类比为版本号。如下:

  • root

    • DIV#4 (V2.1)

    • DIV#5 (V2.3)

    • DIV#6 (V2.4)

    • DIV#1 (V3)

    • DIV#2 (V2)

    • DIV#3 (V1)

    • DIV#8 (V4)

如上,类比成版本号之后,我们就能很方便的判断出谁上谁下啦。

五、注意事项

1. z-index: 0z-index: auto 并不相同。

通常情况下,相邻的两个元素,如果其 z-index 值分别为 0auto ,看上去没什么区别的。如下例 8 所示。

DIV#1 的 z-index 值为 0,其堆叠顺序并没有高于 DIV#2,而是和出现顺序相同。

jamUBje.png!web 示例8 - zindex: 0 和 auto 的区别

点击 CSS 的“层”峦“叠”翠 - 示例 8 - zindex: 0 和 auto 的区别 [8] 查看示例

但是实际上,这两种情况并不相同。上面提到,当元素“ position 值为"absolute"或"relative",且 z-index 指定了除了 auto 以外值”时,元素会产生一个堆叠上下文,虽然元素本身堆叠顺序没有影响,但是其子元素的堆叠顺序会有影响。如下例 9 所示。

因为 DIV#1 的 z-index 值不为 auto,其产生了堆叠上下文,所以其子元素被限制在其内部,低于 DIV#2(如果 z-index 是 auto 的话,DIV#3 会高于DIV#2)。

2EF77nY.png!web 示例9 - zindex: 0 和 auto 的区别(2)

点击 CSS 的“层”峦“叠”翠 - 示例 9 - zindex: 0 和 auto 的区别(2) [9] 查看示例

2. 不要滥用 z-index,将堆叠上下文的层级结构打平

笔者之所以这样建议,是因为当堆叠上下文的层级结构比较复杂时,简单的修改某个元素的 z-index 或者其他属性,会导致一些无法预知的影响。

如下例所示,DIV#2 是 DIV#1 的子元素,DIV#4 是 DIV#3 的子元素,DIV#1 和 DIV#3 不是堆叠上下文,则 DIV#2 与 DIV#4 的堆叠顺序与它们的 z-index 值对应。

UBJBNrM.png!web 示例10 - zindex造成的影响

点击 CSS 的“层”峦“叠”翠 - 示例 10 - zindex 造成的影响 [10] 查看示例

但如果我们在某些时候需要调整 DIV#3 的 z-index,如将其调整成 z-index: 4; ,那么结果就完全不一样了。如下例 11 所示,DIV#4 高于 DIV#2 了。

b2eM73E.png!web 示例11 - zindex造成的影响(2)

点击 CSS 的“层”峦“叠”翠 - 示例 11 - zindex 造成的影响(2) [11] 查看示例

所以笔者建议,大家一定要慎用,基于对堆叠上下文的理解基础上,把握好页面中堆叠上下文的层级结构,尽量保持比较浅的层级结构,最好能与 HTML 层级结构一致,保证自己能够时刻知道如何进行修改与调整。

总结

以上,笔者从元素的默认堆叠顺序,讲到了堆叠上下文的生成。对上述内容了解之后,就能够很好地应对开发中所遇到的层级问题了。不过还是建议大家在开发前,提前规划好 z-index 的使用。避免最后自己无法掌控。

参考文献

  1. 深入理解 CSS 中的层叠上下文和层叠顺序 [12]

  2. Understanding CSS z-index [13]

参考资料

[1]

CSS 的“层”峦“叠”翠 - 示例 1 - 用法导引: https://codepen.io/verymuch/pen/jdNwOW/

[2]

CSS 的“层”峦“叠”翠 - 示例 2 - 无 z-index 时的默认堆叠: https://codepen.io/verymuch/pen/KJPvpQ/

[3]

CSS 的“层”峦“叠”翠 - 示例 3 - flex 中 order 对出现顺序的影响: https://codepen.io/verymuch/pen/RvbjQX/

[4]

CSS 的“层”峦“叠”翠 - 示例 4 - 浮动块的堆叠: https://codepen.io/verymuch/pen/pGogMq/

[5]

CSS 的“层”峦“叠”翠 - 示例 5 - 非定位元素的后代行内元素: https://codepen.io/verymuch/pen/PVoOoX/

[6]

CSS 的“层”峦“叠”翠 - 示例 6 - 使用 z-index 自定义堆叠顺序: https://codepen.io/verymuch/pen/bzGYqb/

[7]

CSS 的“层”峦“叠”翠 - 示例 7 - 存在多级堆叠上下文时,元素的堆叠: https://codepen.io/verymuch/pen/QYbPvN/

[8]

CSS 的“层”峦“叠”翠 - 示例 8 - zindex: 0 和 auto 的区别: https://codepen.io/verymuch/pen/omKOmM/

[9]

CSS 的“层”峦“叠”翠 - 示例 9 - zindex: 0 和 auto 的区别(2): https://codepen.io/verymuch/pen/yZmrWg/

[10]

CSS 的“层”峦“叠”翠 - 示例 10 - zindex 造成的影响: https://codepen.io/verymuch/pen/zbOwxP/

[11]

CSS 的“层”峦“叠”翠 - 示例 11 - zindex 造成的影响(2): https://codepen.io/verymuch/pen/WmejjG/

[12]

深入理解 CSS 中的层叠上下文和层叠顺序: https://www.zhangxinxu.com/wordpress/2016/01/understand-css-stacking-context-order-z-index/

[13]

Understanding CSS z-index: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index

如果你喜欢,欢迎扫码关注我的公众号,如果能够转发分享那就更好了。我会定期陪读,原创&分享一些其他的前端知识,期待与你共同进步。

扫描二维码

获取更多精彩

歪码行空

JzqYfei.jpg!web

写留言

最后让我知道你在看吧


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK