美文网首页
深入浅出 CSS 层叠上下文

深入浅出 CSS 层叠上下文

作者: 西山以南 | 来源:发表于2019-06-20 21:48 被阅读0次

我们在编写 CSS 样式时不少遇到这样的疑惑:“为什么这个元素会被覆盖?”、“为什么设置较高的 z-index 值还是不起效果?”

不妨先想想这个问题,当多个 HTML 元素在浏览器视窗中发生重叠时,浏览器会怎么安排哪个元素显示在上、哪个显示在下呢?其实所有元素在发生层叠时的表现都是按照一定的优先级顺序的,这些顺序规则都是建立在 层叠上下文(The Stacking Context) 这个三维概念中,我们一起来了解下。

层叠上下文特性

  • 在同一个层叠上下文中,子元素按照 层叠顺序 规则进行层叠;

    <style>
    .wrapper {
      position: relative;
      z-index: 1;
    }
    .wrapper div:nth-of-type(1) {
      position: relative;
      z-index: -1;
    }
    .wrapper div:nth-of-type(2) { display: block; }
    .wrapper div:nth-of-type(3) { float: left; }
    .wrapper div:nth-of-type(4) { display: inline-block; }
    .wrapper div:nth-of-type(5) { position: relative; }
    .wrapper div:nth-of-type(6) {
      position: absolute;
      z-index: 1;
    }
    </style>
    
    <body>
      <div class="wrapper">
        <div>position: relative;<br>z-index: -1;</div>
        <div>display: block;</div>
        <div>float: left;</div>
        <div>display: inline-block;</div>
        <div>position: relative;</div>
        <div>position: absolute;<br>z-index: 1;</div>
      </div>
    </body>
    

    关于 层叠顺序 的详解请往下看,完整代码已上传 CodePen:https://codepen.io/JunreyCen/pen/WqoLmr

    另外,当不同层叠顺序的元素相比较时,不关心元素在 DOM 树中的结构关系:

    <style>
    .child {
      position: relative;
      z-index: -1;
    }
    </style>
    
    <div class="parent">
      <div class="child"></div>
    </div>
    <div class="parent" style="opacity: 0.6;">
      <div class="child"></div>
    </div>
    

    左边实例中 Parent 元素不是层叠上下文元素,所以和 Child 元素是处于同一个层叠上下文中,而根据层叠顺序,普通流块级元素 是叠在 z-index 定位元素 之上的。右边实例中 Parent 元素指定属性 opacity: 0.6,创建了一个层叠上下文,从而使 Child 元素包含在内,根据层叠顺序 z-index 定位元素 会叠在 根元素背景和边框 之上。这样的表现说明,ParentChild 元素的父子节点关系不会影响层叠关系。

  • 在同一个层叠上下文中,当元素的层叠顺序相同时,按照 元素在 HTML 中出现的顺序 进行层叠;

    <style>
    .box-1 {
      position: relative;
    }
    .box-2 {
      position: absolute;
      top: 50px;
      left: 50px;
    }
    </style>
    
    <div class="wrapper">
      <div class="box-1"></div>
      <div class="box-2"></div>
    </div>
    <div class="wrapper">
      <div class="box-2"></div>
      <div class="box-1"></div>
    </div>
    

    所有 z-index 属性值为 0 / auto 的定位元素的层叠顺序都是相同的,如实例中的 box-1box-2 元素,可以看出它们发生层叠时遵循的是 在 HTML 中出现的先后顺序

  • 层叠上下文支持嵌套,子级层叠上下文对于父级层叠上下文是一个独立单元,对于兄弟元素来说也是相互独立的;

  • 每个层叠上下文都是自包含的,无论在子级层叠上下文内如何 “翻云覆雨”,也是基于父级层叠上下文的层叠顺序下;

    <style>
    .parent-1,
    .parent-2,
    .child-1, 
    .child-2 {
      position: relative;
    }
    .parent-1 { z-index: 2; }
    .parent-2 { z-index: 1; }
    .child-1 { z-index: -1; }
    .child-2 { z-index: 10; }
    </style>
    
    <div class="parent-1">
      <div class="child-1"></div>
    </div>
    <div class="parent-2">
      <div class="child-2"></div>
    </div>
    

    Child-1Child-2 元素分别处于各自的父级层叠上下文元素 Parent-1Parent-2 中。由于 Parent-1 是层叠于 Parent-2 之上的,即使 Child-1z-index: -1 属性值小于 Child-2z-index: 10Child-2 也不能逾越其父级上下文覆盖在 Child-1 上面的。换句话说,子级层叠上下文的层级讨论只在其父级层叠上下文中有意义。

创建层叠上下文

满足以下 12 个条件中任意一个的元素会创建一个层叠上下文(摘自 MDN ):

1、根元素 <html>
2、z-index 值不为 auto 的相对定位(position: relative)和绝对定位(position: absolute);
3、固定定位(position:fixed);
4、z-index 值不为 auto 的伸缩盒模型中的 flex 项目;
5、opacity 属性值小于 1
6、transform 属性值不为 none
7、filter 属性值不为 none
8、mix-blend-mode 属性值不为 normal
9、perspective 属性值不为 none
10、isolation 属性值为 isolate
11、will-change 属性 指定了上述任意一个 CSS 属性(即便没有直接指定这些属性的值)
12、-webkit-overflow-scrolling 属性值为 touch

关于第 11 点中的 will-change 属性:该属性主要用于告知浏览器元素会发生哪些变化,有利于浏览器在元素真正变化之前提前做好优化准备。所以当 will-change 指定了能创建层叠上下文的 CSS 属性(包括 z-index 属性)时,浏览器也会为该元素创建层叠上下文。

层叠顺序

层叠顺序就是元素在层叠上下文中的显示规则。在此之前需要提前认识一个重要概念:z-index 只会对定位元素(非普通流)有效

当元素发生层叠时,会按照下面的 7 阶层叠顺序来决定元素显示的前后顺序:

1、根元素的背景与边框;
2、z-index < 0 的定位元素;
3、普通流中的块元素(display: block);
4、浮动块元素;
5、普通流中的行内元素(display: inline / display: inline-block);
6、z-index 属性值为 0 / auto 的定位元素、其他子级层叠上下文元素;
7、z-index > 0 的定位元素;

  • 普通流:不指定 position 或者 position: static
  • 上面第 6 点中的 其他 子级层叠上下文元素:不依赖 z-index 属性就能创建层叠上下文的元素;
7 阶层叠顺序图

注意事项

  • 层叠顺序的第 6 阶中,z-index 属性值为 0 / auto 的定位元素不依赖 z-index 的子级层叠上下文元素 顺序相同,会遵循 在 HTML 中出现的先后顺序 来层叠;

    <div class="wrapper">
      <div class="box-1" style="opacity: 0.8;"></div>
      <div class="box-2" style="position: absolute;"></div>
    </div>
    <div class="wrapper">
      <div class="box-2" style="position: absolute;"></div>
      <div class="box-1" style="opacity: 0.8;"></div>
    </div>
    
  • 伸缩盒没有创建层叠上下文,伸缩盒中 z-index 值不为 auto 的 flex 项目才会创建层叠上下文。换句话说,使用这种方式创建层叠上下文需要同时满足两个条件:

    1. 父元素设置了display: flex / display: inline-flex
    2. 自身 z-index 属性值不为 auto;
    <style>
    .child {
      position: relative;
      z-index: -1;
    }
    </style>
    
    <div class="container">
      <div class="item">
        <div class="child"></div>
      </div>
    </div>
    <div class="container" style="display: inline-flex;">
      <div class="item" style="z-index: 1;">
        <div class="child"></div>
      </div>
    </div>
    <div class="container" style="display: inline-flex;">
      <div class="item" style="z-index: -1;">
        <div class="child"></div>
      </div>
    </div>
    

    左边实例,ContainerItem 元素都没有创建层叠上下文,这两者与 Child 元素都处于同一个层叠上下文中,按照层叠顺序渲染;

    中间实例,Container 元素设置 display: inline-flex 成为 Flex 容器,Item 元素设置 z-index: 1,则 Item 元素创建了层叠上下文,所以即使 Child 元素的 z-index 值为负数,却依然层叠在 Item 元素之上;

    右边实例,把 Item 元素的 z-index 值改为 -1,由于 Container 元素作为 Flex 容器是没有创建层叠上下文的,所以 Item 元素会层叠在 Container 元素之下。

固定定位(position: fixed)的特殊性

我们发现,单纯是绝对/相对定位元素是无法创建一个层叠上下文的,需要同时满足 z-index 值不为 auto 的条件。然而,固定定位元素就不需要满足这个条件,显得尤为特殊。

  • 固定定位元素无需满足 z-index 值不为 auto 的条件就可以创建层叠上下文;同样地,设置 z-index: auto 并不能撤销固定定位元素所创建的层叠上下文。

    <style>
    .fixed {
      position: fixed;
      z-index: auto;
    }
    .child {
      position: relative;
      z-index: -1;
    }
    </style>
    <div class="fixed">
      <div class="child"></div>
    </div>
    
  • 正常情况下,固定定位是相对于浏览器视窗(viewport)进行定位的,但是当其祖先元素中存在符合以下任意一个条件的元素时,固定定位元素会相对于该元素进行定位:

    1、transform 属性值不为 none;
    2、transform-style: preserve-3d
    3、perspective 属性值不为 none
    4、will-change 属性 指定了上面 3 个 CSS 属性中的任意一个

    然而,这种表现在不同的浏览器中有差异,譬如在 Safari 中只有上述第 1 点会对固定定位元素产生影响。

建议

通过对层叠上下文和层叠顺序的了解,我们知道,要控制元素间的层叠关系除了使用 z-index 属性外还有很多途径,而且比使用 z-index 要优雅得多。滥用 z-index 往往只会把层叠关系复杂化,造成代码难以维护。

友情链接

学习完 CSS 层叠上下文,如果对 BFC(块格式化上下文)、IFC(行内格式化上下文)等相关概念有兴趣的,可以学习这篇文章:视觉格式化模型 | MDN

文中涉及到的完整实例代码已放在 Github 上,欢迎大家交流。

Reference

相关文章

  • 深入浅出 CSS 层叠上下文

    我们在编写 CSS 样式时不少遇到这样的疑惑:“为什么这个元素会被覆盖?”、“为什么设置较高的 z-index 值...

  • CSS深入浅出(4)-层叠上下文和层叠顺序

    层叠顺序 先创建一个div背景添加一个border,这时候看看谁离用户更近一点。image.png更改背景颜色,发...

  • CSS:层叠上下文

    层叠顺序: 层叠上下文(border/background)< 负z-index < block块状盒子 < 浮动...

  • css层叠上下文

    一、层叠上下文 上下文定义: ① 一个参与多方构建的,遵循一定规则的,独立的环境②子项可能创建新的独立的环境,与外...

  • web面试相关

    css 1、盒模型 2、flex 3、css单位 4、css选择器 5、bfc 清除浮动 6、层叠上下文 7、常见...

  • 2019-07-06 层叠上下文的创建

    层叠上下文的创建   和块状格式化上下文一样,层叠上下文也基本上是由一些特定的CSS属性创建的。我将其总结为3个流...

  • 细读 CSS | 层叠上下文

    在 HTML 页面中,我们通常会使用 margin、float、offset 等 CSS 属性控制元素在 X 轴和...

  • 层叠上下文

    层叠顺序 说到层叠上下文要先引出一个层叠顺序的概念。CSS中所有的元素默认有以下的层叠顺序,如果是兄弟元素的话,默...

  • 2019前端面试题--这样准备,拿不到offer算我输!

    前言 css 1、盒模型2、flex3、css单位4、css选择器5、bfc 清除浮动6、层叠上下文7、常见页面布...

  • z-index和层叠上下文

    一、 层叠上下文、层叠等级和层叠顺序 层叠上下文(stacking context)层叠上下文是HTML中一个三维...

网友评论

      本文标题:深入浅出 CSS 层叠上下文

      本文链接:https://www.haomeiwen.com/subject/awjatctx.html