Css层叠优先级只会这两招还远远不够!

1,072 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

作为一个玩前端的,ps软件中的图层都知道吧,多个图层层叠就可以组成丰富多彩的图片,所以图层就有层叠顺序了,Css的层叠原理也是差不多,只不过Css是通过多个盒子层叠形成丰富多彩的图片,Css层叠优先级设置不就是z-index!important吗?是的,就是这两招,这两个Css属性应该是见怪不怪,因为这是我们只要写Css样式都会用到,那么它们有什么区别?

  • z-index一个元素在文档中的层叠顺序,用于确认元素在当前层叠上下文中的层叠级别。
  • !important提升指定样式规则的应用优先权,也可以理解为增加样式权重的方法,只要给元素属性值后面带上这个就会使当前设置的样式有最高优先级。

!important这个相信不用我们多花时间去理解都知道,反正它就是最高优先级,但是z-index的优先级相信很多人都是停留在它的值越高优先级越高,这样理解也没错,比如以下例子:

image.png 上图中展示确实看到了,z-index越大,层叠越高,但是我们有没有想过z-index的作用仅仅限于此吗?大错特错!我们看看下面三个例子:

  • z-index越小反而层叠优先级越高,效果跟上图一致,为什么?

    .parent1 {
      ...
      z-index: 2;
    }
    
    .parent2 {
      ...
      z-index: 1;
    }
    
  • 给设置了z-index属性的盒子都添加了定位属性,为什么大小又生效了?

    image.png

  • z-index大小对于元素的样式层叠优先级完全没有顺序可言,为什么会这样?

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <style>
            .parent1 {
                  width: 300px;
                  height: 200px;
                  background-color: #fa6800;
            }
            .middle {
                  width: 300px;
                  height: 200px;
                  background-color: #e3c800;
                  margin-left: 50px;
                  margin-top: -50px;
                  z-index: 2;
                  position: relative;
            }
            .parent2 {
                  width: 300px;
                  height: 200px;
                  margin-top: -50px;
                  background-color: #f0a30a;
                  z-index: 1;
                  position: relative;
            }
            .parent2-child1 {
                  width: 300px;
                  height: 200px;
                  left: 180px;
                  top: -50px;
                  background-color: #a20025;
                  position: absolute;
                  z-index: 5;
            }
      </style>
    </head>
    
    <body>
          <div class="parent1"></div>
          <div class="middle"></div>
          <div class="parent2">
                <div class="parent2-child1"></div>
          </div>
    </body>
    </html>
    

    image.png

从上面三个例子中,我们可能会说z-index好像没啥用?其实不然,只是我们没有掌握它其中的精粹,我们之前的理解z-index越大层叠优先级越高,也是电脑屏幕上的三维坐标图,z-index值越大在z轴上就越大,也就是说离屏幕观察者越近。其实z-index不仅仅受大小值影响,还会受其他因素的影响,z-index设置每个元素的层叠顺序是由元素所属上下文元素本身的层叠水平(等级/级别)决定的,注意地,每个元素仅属于一个层叠上下文。

image.png

什么是层叠上下文?

  • 层叠上下文stacking context。是HTML中的一个三维概念,如果一个元素含有层叠上下文,我们可以理解为这个元素在z轴上就“高人一等”。一般情况下,当我们开发网页的时候,我们能看到的就是元素在页面上沿x轴y轴平铺,我们根本察觉不到元素在z轴上的层叠关系。因为这是观察者与元素显示位置的垂直距离,是抽象的。那么问题来了,层叠上下文是如何产生的?
    • HTML文档的根元素html标签本身就是层叠上下文(根层叠上下文)。

    • 普通元素设置position属性为非static值设置了z-index属性为具体数值,这样就产生了层叠上下文。(比如上面的例子2,遵循层叠上下文中z-index大小,谁打谁居上)

    • CSS3新属性也可以产生层叠上下文。只要符合以下条件之一,就会产生层叠上下文:

      // 1 父元素为display或者display: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指定的属性值为上面任意一个
      // 8 元素的-webkit-overflow-scrolling设为touch
      

什么是层叠水平?

  • 层叠水平stacking level。层叠水平指的就是:
    • 在同一层叠上下文,它代表就是该层叠上下文中的层叠上下文元素在Z轴上的上下顺序;如下面例子中,同一层叠上下文.parent中,该层叠上下文中的层叠上下文元素有a、b,由于a的z-index大于b的z-index,所以a盒子在最上面。

      image.png

    • 在其他普通元素,它代表的就是这些普通元素在Z轴上的上下顺序;在下图中没有层叠上下文元素,都是普通元素,我们可以发现,元素是从上到下,后来者居上

      image.png

什么是层叠顺序?

  • 层叠顺序stacking order,层叠顺序上面已经说了是由元素层叠上下文元素层叠水平决定,也就是遵循下图层叠顺序: image.png 从上面层叠上下文概念中,如果普通元素一旦有了层叠上下文,其层叠顺序就会提高,因为:
  • 如果层叠上下文元素不依赖z-index值,那么z-index:auto可以看成z-index:0,从而使层叠上下文元素层叠顺序提高了
  • 如果层叠上下文元素依赖z-index值,层叠顺序由z-index值决定

    一旦普通元素成为定位元素,z-index就会自动生效。

结合概念举例子

🍉栗子1:Css3新属性影响层叠上下文,比如下面transform例子:如果没有添加transform属性,parent1盒子覆盖a盒子,因为div是块级元素层叠水平,而a盒子的层叠水平为负z-index;如果添加transform属性就会使parent1盒子变成层叠上下文,负z-index值大于层叠上下文层叠水平,所以a盒子会在最上。

image.png

.parent1 {
      width: 300px;
      height: 200px;
      background-color: #fa6800;
      /* transform: rotate(90deg); */
}

.a {
      width: 100px;
      height: 100px;
      left: 20px;
      top: 20px;
      background-color: cyan;
      position: relative;
      z-index: -1;
}


<div class="parent1">
    <div class="a"></div>
</div>

🍉栗子2:开始地例子3,z-index大小对于元素的样式层叠优先级完全没有顺序可言,为什么会这样?

  • parent1盒子是块级元素div。
  • middle盒子是定位元素并依赖z-index值,z-index: 2
  • parent2盒子是定位元素并依赖z-index值,z-index: 1
  • parent2-child1盒子是定位元素并依赖z-index值,z-index: 5

由于parent2-child1盒子是parent2盒子的子元素,而且它们都是层叠上下文,而层叠上下文可以嵌套,内部层叠上下文及其所有子元素均受制于外部的层叠上下文。 所以parent2-child1盒子覆盖parent2盒子,但是又不能覆盖middle(z-index:2),因为每个层叠上下文是自成体系的,当元素发生层叠的时候,整个元素被认为是在父层叠上下文的层叠顺序中。,也就是说z-index值为5的parent2-child1盒子层叠顺序受parent2盒子的影响,所以虽然它的z-index最高,但是会受父层叠上下文元素的影响。 image.png

总结:

其实,层叠准则只要牢记下面两个准则就行:

  • 谁大谁最上:只要有明显层叠水平标志时,如z-index值;在同一层叠上下文,大的覆盖小的哪一个。
  • 后来者居上:元素层递水平一致、层叠顺序相同,只看处于DOM流后面的元素。

参考资料: