5分钟搞懂z-index与层叠上下文

2,505 阅读5分钟

前言

相信每一个前端小伙伴都使用 z-index 来做过一些蒙版的层级控制,但是你是否了解层叠上下文这个概念呢,你在使用 z-index 来控制层级的时候,有没有遇到过一些想不通的问题呢?如果有的话,不妨花点时间来了解 CSS 中的层叠规则。

一个小问题

现在设计提供了一个分享卡片样式:

要实现红框中的样式,我们应该很自然的想到使用伪元素来给标题添加这个带有渐变色的自定义下划线。简化代码如下:

<body>
    <div class="card">
        <div class="title">
            我有下划线
        </div>
    </div>
</body>
<style>
.card{
    background:#fff;
}
.title {
    position: relative;
    width: 100px;
}
.title::before {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 8px;
    background-image: linear-gradient(to left, rgb(238, 218, 148), rgb(217, 179, 91));
}
</style>

页面效果如下:

因为伪元素是绝对定位,所以挡在了文字的前面,所以应该改变伪元素的层叠顺序,给伪元素添加样式:z-index:-1,即:

.title::before {
    content: '';
    ...
    z-index:-1;
}

再次查看页面效果:

咦,下划线呢?木了,同学,你看到我的下划线了吗?接下来,我们一起把消失的下划线揪出来吧。

层叠上下文

层叠上下文,英文称作 stacking context,是 HTML 中的一个三维的概念。如果一个元素含有层叠上下文,我们可以理解为这个元素在 z 轴上就“高人一等”。我们可以把层叠上下文理解为一种“层叠结界”,自成一个小世界。在这个层叠结界中,所有的层叠元素都不会溢出这个结界,并在其内部满足一定的层叠规则:

background/border 为装饰属性,浮动和块状元素一般用作布局,而内联元素都是内容。这里需要注意的是,负 z-index 的元素在层叠顺序上是高于 background 的,即使将一个元素的 z-index 设置为-99999,它仍然会出现在所处的层叠上下文的背景之上。

层叠上下文的特性

 层叠上下文的层叠水平要比普通元素高
 层叠上下文可以阻断元素的混合模式
 层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的“层叠上下文”。
 每个层叠上下文和兄弟元素独立,也就是说,当进行层叠变化或渲染的时候,只需要考虑后代元素。
 每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。

层叠上下文的创建

层叠上下文可以由以下几种方式创建:

  1. 页面根元素天生具有层叠上下文,又称为根层叠上下文;
  2. 给元素设置 z-index 值为数值的定位元素;
  3. 给元素设置特定的 CSS3 属性,也会使其成为层叠上下文;

根层叠上下文

根层叠上下文指的是页面根元素,可以看成是元素。因此,页面中所有的元素一 定处于至少一个“层叠结界”中。

z-index 为数值的定位元素

对于 position 值为 relative/absolute 以及 Firefox/IE 浏览器(不包括 Chrome 浏览 器)下含有 position:fixed 声明的定位元素,当其 z-index 值不是 auto 的时候,会创建 层叠上下文。换言之,想让 z-index 对元素的层叠顺序生效,前提是该元素得是定位元素,否则根本都不会创建层叠上下文。

CSS3 属性创建的层叠上下文

  1. 元素为 flex 布局元素(父元素 display:flex|inline-flex),同时 z-index 值不是 auto。
  2. 元素的 opacity 值不是 1。
  3. 元素的 transform 值不是 none。
  4. 元素 mix-blend-mode 值不是 normal。
  5. 元素的 filter 值不是 none。
  6. 元素的 isolation 值是 isolate。
  7. 元素的 will-change 属性值为上面 2~6 的任意一个(如 will-change:opacity、will-chang:transform 等)。
  8. 元素的-webkit-overflow-scrolling 设为 touch。

层叠上下文与层叠顺序

因为根层叠上下文的存在,所有所有页面元素至少存在于一个层叠上下文中,并在其中满足一下规律:

  1. 如果层叠上下文元素不依赖 z-index 数值,则其层叠顺序是 z-index:auto,可看成 z:index:0 级别;由 CSS3 属性创建的层叠上下文属于此类情况;
  2. 如果层叠上下文元素依赖 z-index 数值,则其层叠顺序由 z-index 值决定。

更完整的 7 阶层叠顺序图:

消失的下划线

最后,我们一起看看消失的下划线去哪儿了,首先看一下页面的 dom 元素层级 body->card->title->title:before,而此时,页面中有两个层叠上下文,根层叠上下文和伪元素通过 z-index:-1 创建的层叠上下文,因为伪元素 z-index 值是负值,查阅层叠顺序图,可以知道伪元素会处于 body 的背景图之上,card(块状水平盒子)之下。而 card 元素的背景设置为纯白色,所以下划线伪元素就被 card 的白色背景挡住了,因此,我们已经找到了消失的下划线,那么怎么让下划线正好展示在文字和 title 元素的背景之间呢,那很简单,只需要给 title 元素设置样式:z-index:0,即给 title 元素创建层叠上下文,样式代码:

.title {
    position: relative;
    width: 100px;
    z-index:0;
}

此时页面效果:

最后

自己试试?codePen

参考:css世界-张鑫旭