1

今天写代码用antd-mobile的checkbox时候,想在内容文本后面添加一个icon,并且需要对这个icon绑定事件,发现绑定之后怎么也点不中,调试发现原来被层层嵌套的dom元素盖住了,肯定是z-index在作祟。可是按照我之前对z-index的了解(自信满满)却怎么也不能把他由“被盖住”改成“盖住别人”,在一通“盲改”代码之后,终于“盖住”其他dom元素了。然而心里总是在想难道之前自己对z-index的认知有问题么,抱着这样的心态决定重新去学习,下面进入正文

90%的前端开发对z-index的认知

其实我想说大部分前端开发是不重视css的,也就导致了对css的很多属性认知都是表面的,这其中z-index就是最典型的一个,下面列举的错误认知还请大家对号入座:

  • z-index值越大越“靠近我们” -- 最初级的认知
  • 要搭配position: absolute | relative | fixed 使用才有用呢 -- 稍微进阶一些的认知
  • 比较两个兄弟节点谁更“靠近我们”,要看他们的同级父元素的比较呢。-- 可能是大部分前端的终极认知了

例如下面的例子:要比较div1-1-1 和 div2-1 是要看div1 和 div2 的比较结果呢

<div class="div1">
    <div>
        <div class="div1-1-1" />
    </div>
</div>
<div class="div2">
    <div class="div2-1" />
</div>

如果以上三个大家都中枪了,没关系,看完这篇文章你就永远告别了,在遇到z-index的问题再也不会“盲改,乱试”了

三个概念 -- 层叠上下文、层叠水平、层叠顺序

  1. 层叠上下文(stacking context)
    看到上下文这个关键词,我想大家应该会有一点概念,没错就是context。和你们认识的那个BFC、IFC里面的上下文是一个意思,其实我想说css世界里面看到context或者XXX上下文其实都是同一个意思,完全可以理解为自成一派,在自己的小世界里面随便折腾,不受其他的context影响。当然,这个context是可以被其他context包含同时也可以包含其他context
  2. 层叠水平(stacking level)
    层叠水平决定了在同一个层叠上下文中元素在Z轴上的显示顺序。
    页面中的所有元素(普通元素和层叠上下文元素)都有层叠水平。然而对普通元素的层叠水平探讨只局限在层叠上下文元素中。
    注:大家千万不要把层叠水平和z-index混为一谈,尽管某些情况下z-index确实可以影响层叠水平,但是也只局限于具有层叠上下文的元素,而层叠水平是所有元素都存在的
  3. 层叠顺序(stacking order)
    层叠顺序表示发生层叠时有着特定的垂直显示顺序(规则)。
    即:网上这张很流行的规则
    clipboard.png

    关于这张图有一些补充:
    位于最下面的background/border特指层叠上下文元素的边框和背景色。每一个层叠顺序规则仅适用当前层叠上下文元素的小世界
    inline水平盒子指的是包括inline/inline-block/inline-table元素的层叠顺序,他们都是同级别的
    单纯从层叠水平上看,实际上z-index:0和auto是可以看成一样的,但是在层叠上下文领域有着根本性的差异

深入了解层叠上下文

  1. 特性

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

  2. 如何创建

    根元素 (HTML)
    z-index 值不为 "auto"的 绝对/相对定位(在firefox/ie浏览器下position: fixed也是可以的)
    一个 z-index 值不为 "auto"的 flex 项目 (flex item),即:父元素 display: flex|inline-flex
    opacity 属性值小于 1 的元素(参考 the specification for opacity)
    transform 属性值不为 "none"的元素
    mix-blend-mode 属性值不为 "normal"的元素
    filter值不为“none”的元素
    perspective值不为“none”的元素
    isolation 属性被设置为 "isolate"的元素
    position: fixed
    在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考这篇文章
    -webkit-overflow-scrolling 属性被设置 "touch"的元素

  3. 层叠上下文与层叠顺序

    文章中多次提到普通元素具备层叠上下文后层叠水平就会变高,那么他究竟在层叠顺序那个规则图的哪个位置呢
    把目光向上锁定,第二条列举了12个可以创建层叠上下文的方法,我们把他分为两类:第二三条和其他。
    依赖z-index取值的:位置取决于z-index的值
    不依赖z-index取值的:在图中第二高的位置,即:z-index = auto 或者 0

    用一个例子来说明:

    <div class="container">
        <div class="div1">111</div>
        <div class="div2">222</div>
    </div>
    .container {
      width: 500px;
      height: 500px;
      background-color: #000;
      color: #fff;
      transform: scale(1); 
      /* 给container创建层叠上下文 */
    }
    .div1 {
      padding: 50px;
      background-color: aqua;
      z-index: 0;
      position: relative;
      /* 给div1创建层叠上下文,层叠水平依赖z-index的取值 */
    }
    .div2 {
      padding: 50px;
      background-color: red;
      opacity: 0.8;
      /* 给div2创建层叠上下文,层叠水平依赖z-index的取值 */
      /* margin-top: -40px; */
    }
    
    

    这个例子中一目了然,div1和div2的层叠水平一样,都是在规则那张图的第二高的位置,不过div2在div1的dom节点后面,所以div2要比div1的层叠水平高,我们把margin-top的注释去掉看下:

    clipboard.png
    要想使得div1在上面只需要把div1的z-index改成大于0的值就好了。

    还是上面的htl结构,接下来我们再来看一个有意思的例子:

    .container {
      width: 500px;
      height: 500px;
      background-color: #000;
      color: #fff;
      transform: scale(1);
      /* 给container创建层叠上下文 */
    }
    .div1 {
      padding: 50px;
      background-color: aqua;
      opacity: 0.8;
      /* 给div1创建层叠上下文,层叠水平在z-index:0 */
    }
    .div2 {
      padding: 50px;
      background-color: red;
      position: relative;
      margin-top: -40px;
    }
    

    大家肯定会说,div1明显盖过div2啊,可是我们来看下实际情况:

    clipboard.png

    实际情况下面的div2盖过了div1,原因是当html元素设置定位属性的时候(absolute/relative),其z-index属性自动生效变成
    z-index: auto,所以这时候div1和div2的层叠水平是一致的,而div2在div1的dom节点后面,所以盖过了div1(注意这里div2并没有变成层叠上下文元素,这是有本质区别的

常见错误认知解析

现在我们在一起看下文章开头提到的几个常见的错误认知:

  • z-index值越大越“靠近我们” -- 并不一定,首先要成为层叠上下文。或者如果比较的元素的父元素也是层叠上下文,那就完全取决于父元素了
  • 要搭配position: absolute | relative | fixed 使用才有用呢 -- 对了一部分,还有其他的条件也可以使元素称为层叠上下文元素
  • 比较两个兄弟节点谁更“靠近我们”,要看他们的同级父元素的比较呢。-- 如果同级父元素不是层叠上下文元素就不需要看“父元素的眼色”了

文章到这里就结束了,希望看完这篇文章的同学可以彻底理解z-index。


wens
272 声望4 粉丝