CSS的“层”峦“叠”翠

前言

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

z-index 的使用彷佛就是这么简单,对吧?前端

咱们先看以下例 1:web

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

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

示例1 - 用法引导
示例1 - 用法引导

点击 CSS的“层”峦“叠”翠 - 示例1 - 用法导引 进行编辑 (@verymuch) on CodePen. 编辑器

如上所示,z-index 为 2 的元素并无显示在第二个元素上面。这彷佛很奇怪,那究竟是为何呢?wordpress

若是你也对此存在困扰,那就和我一块儿往下看吧。笔者将逐步引导你们深刻理解 z-index 的用法。布局

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

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

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

  1. 根元素的背景和边框
  2. 非定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠
  3. 定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

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

示例2 - 无z-index时的默认堆叠
示例2 - 无z-index时的默认堆叠

点击 CSS的“层”峦“叠”翠 - 示例2 - 无z-index时的默认堆叠 进行编辑 (@verymuch) on CodePen.

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

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

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

示例3 - flex中order对出现顺序的影响
示例3 - flex中order对出现顺序的影响

点击 CSS的“层”峦“叠”翠 - 示例3 - flex中order对出现顺序的影响 进行编辑 (@verymuch) on CodePen.

2、浮动块默认如何堆叠

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

  1. 根元素的背景和边框
  2. 非定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠
  3. 浮动块
  4. 定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

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

示例4 - 浮动块的堆叠
示例4 - 浮动块的堆叠

点击 CSS的“层”峦“叠”翠 - 示例4 - 浮动块的堆叠 进行编辑 (@verymuch) on CodePen.

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

  1. 根元素的背景和边框
  2. 非定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠
  3. 浮动块
  4. 非定位元素的后代行内元素
  5. 定位的后代块元素,按照在 HTML 中的出现顺序进行堆叠

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

示例5 - 非定位元素的后代行内元素
示例5 - 非定位元素的后代行内元素

点击 CSS的“层”峦“叠”翠 - 示例5 - 非定位元素的后代行内元素 进行编辑 (@verymuch) on CodePen.

3、使用 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 对其有影响,堆叠顺序与数字大小符合。

示例6 - 使用z-index自定义堆叠顺序
示例6 - 使用z-index自定义堆叠顺序

点击 CSS的“层”峦“叠”翠 - 示例6 - 使用z-index自定义堆叠顺序 进行编辑 (@verymuch) on CodePen.

好了,相信经过上述内容,你们对于 z-index 应该有了必定的了解,可是以上仅仅是基本知识,关于堆叠远远没有这么简单。

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

4、堆叠上下文

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

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

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

若是任何一个元素知足一下条件之一,就会生成一个堆叠上下文。

  1. 文档的根元素(HTML)默认为一个堆叠上下文
  2. position值为"absolute"或"relative",且 z-index 指定了除了 auto 之外值的元素
  3. position值为"fixed"或"sticky"
  4. 弹性布局的子元素,且 z-index 指定了除了 auto 之外值的元素
  5. opacity的值小于的元素
  6. mix-blend-mode的值不是 normal的元素
  7. 如下属性值不为"none"的元素
    • transform
    • filter
    • perspective
    • clip-path
    • mask / mask-image / mask-border
  8. isolation值为"isolate"的元素
  9. -webkit-overflow-scrolling值为"touch"的元素
  10. will-change指定了除初始值之外的任何属性的元素
  11. contain值为"layout"/"paint"及含义其中之一的组合值的元素

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

对于堆叠上下文咱们须要知道如下几点:

  1. 在每一个堆叠上下文内部,子元素的堆叠规则遵循上面所讲的基本规则。
  2. 堆叠上下文能够包含在其余堆叠上下文内部,它们会建立一个堆叠上下文层级结构。
  3. 堆叠上下文的层级结构与 HTML 的元素不一样,由于对于没有建立堆叠上下文的元素会被父元素同化。 堆叠上下文的层级只包括建立了堆叠上下文的元素
  4. 堆叠上下文独立于其兄弟元素,在处理自身内部堆叠时,只考虑其后代元素。内部堆叠完成后,将当前堆叠上下文当成一个总体,考虑在父堆叠上下文中的堆叠顺序。通俗的说, 子堆叠上下文的 z-index 值只在父堆叠上下文中有意义。

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

针对这几点,咱们看一下例 7。你们能够先看一下是否理解。而后咱们再讲解一下。

示例7 - 存在多级堆叠上下文时,元素的堆叠
示例7 - 存在多级堆叠上下文时,元素的堆叠

点击 CSS的“层”峦“叠”翠 - 示例7 - 存在多级堆叠上下文时,元素的堆叠 进行编辑 (@verymuch) on CodePen.

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

  • root
    • DIV#1
    • DIV#2
      • DIV#4
      • DIV#5
      • DIV#6
    • 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#1 (V3)
    • DIV#2 (V2)
      • DIV#4 (V2.1)
      • DIV#5 (V2.3)
      • DIV#6 (V2.4)
    • DIV#3 (V1)
    • DIV#8 (V4)

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

5、注意事项

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

一般状况下,相邻的两个元素,若是其 z-index 值分别为0auto,看上去没什么区别的。以下例 8 所示。

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

示例8 - zindex: 0 和 auto 的区别
示例8 - zindex: 0 和 auto 的区别

点击 CSS的“层”峦“叠”翠 - 示例8 - zindex: 0 和 auto 的区别 进行编辑 (@verymuch) on CodePen.

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

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

示例9 - zindex: 0 和 auto 的区别(2)
示例9 - zindex: 0 和 auto 的区别(2)

点击 CSS的“层”峦“叠”翠 - 示例9 - zindex: 0 和 auto 的区别(2) 进行编辑 (@verymuch) on CodePen.

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

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

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

示例10 - zindex形成的影响
示例10 - zindex形成的影响

点击 CSS的“层”峦“叠”翠 - 示例10 - zindex形成的影响 进行编辑 (@verymuch) on CodePen.

但若是咱们在某些时候须要调整 DIV#3 的 z-index,如将其调整成z-index: 4;,那么结果就彻底不同了。以下例 11 所示,DIV#4 高于 DIV#2 了。

示例11 - zindex形成的影响(2)
示例11 - zindex形成的影响(2)

See the Pen CSS的“层”峦“叠”翠 - 示例11 - zindex形成的影响(2) by verymuch (@verymuch) on CodePen.

因此笔者建议,你们必定要慎用,基于对堆叠上下文的理解基础上,把握好页面中堆叠上下文的层级结构,尽可能保持比较浅的层级结构,最好能与 HTML 层级结构一致,保证本身可以时刻知道如何进行修改与调整。

总结

以上,笔者从元素的默认堆叠顺序,讲到了堆叠上下文的生成。对上述内容了解以后,就可以很好地应对开发中所遇到的层级问题了。不过仍是建议你们在开发前,提早规划好 z-index 的使用。避免最后本身没法掌控。

参考文献

  1. 深刻理解 CSS 中的层叠上下文和层叠顺序
  2. Understanding CSS z-index

若是你喜欢,欢迎扫码关注个人公众号,我会按期陪读,并分享一些其余的前端知识。

相关文章
相关标签/搜索