10分钟了解z-index机制

1,591 阅读3分钟

前言

俾众周知,CSS是前端的一门DSL语言,虽然不具备图灵完备,但是它在样式渲染这一领域里更加形象的描述了一个事物,在当下娱乐、信息、多元化时代背景下CSS的地位越发凸显,今天我们来聊聊CSS中的Z-index属性

回顾Z-index的例子

 <div class="box1"></div>
 <div class="box2"></div>
 .box1 {
   width: 100px;
   height: 100px;
   background: red;
   position: relative;
   z-index: 1;
 }
 .box2 {
   width: 100px;
   height: 100px;
   background: blue;
   position: relative;
   bottom: 50px;
 }

展示效果如下: 1.png 以上例子是我们经常用到的z-index例子,原本是按照渲染顺序,box1应该处于box2下面,但是box1利用了z-index提升自己的层级,从而达到了box1覆盖在box2上面

再来看一个例子

根据上面例子,我们将box1的position给删除掉

 .box1 {
  - position: relative;
}

我们再来看例子,发现box1又被覆盖到了box2下面,z-index失效了, 这里有暗示着z-index与某个特殊机制会存在着关系,我们继续往下看

层叠上下文

我们在面对viewport的时候,虽然是平面的,但其实viewport是一个三维空间,它分为x、y、z三个轴,z-index会在三维空间里的z轴添加不同的渲染层,从而达到覆盖效果,这里css有个隐藏机制 ———— 层叠上下文,创建层叠上下文的机制如下:

  • 文档根元素;
  • position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index 值不为 auto 的元素;
  • position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);
  • flex (flexbox (en-US)) 容器的子元素,且 z-index 值不为 auto;
  • grid (grid) 容器的子元素,且 z-index 值不为 auto;
  • opacity 属性值小于 1 的元素(参见 the specification for opacity);
  • mix-blend-mode 属性值不为 normal 的元素;

以下任意属性值不为 none 的元素:

  • transform
  • filter
  • perspective
  • clip-path
  • mask / mask-image / mask-border
  • isolation 属性值为 isolate 的元素;
  • -webkit-overflow-scrolling 属性值为 touch 的元素;
  • will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章);
  • contain 属性值为 layout、paint 或包含它们其中之一的合成值(比如 contain: strict、contain: content)的元素。

消除误会

以前我们在使用z-index的时候经常会添加上position来配合使用,但其实z-index触发的机制根本原因不在于position,而是在position创建的层叠上下文,看以下例子

 <div class="box1 flex">
  <div class="innerBox"></div>
 </div>
 <div class="box2">
 </div>
 .box1 {
   width: 100px;
   height: 100px;
 }

 .box1.flex {
   display: flex;
 }

 .box1 .innerBox {
   width: 100%;
   height: 100%;
   z-index: 2;
   background: red;
 }
 
 .box2 {
   width: 100px;
   height: 100px;
   background: blue;
   position: relative;
   bottom: 50px;
 }

展示效果如下:

微信截图_20210315134545.png 我们可以发现innerBox覆盖在了box2上面,但是innerBox并没有使用position布局,z-index还是起效了,而flex布局在子元素z-index不为auto时会创建一个层叠上下文,这也证明了z-index其实是依附于层叠上下文

拉平层级

我们有时候能看到z-index: 99无法覆盖z-index: 1的情况,这是为什么,我们改编以上例子,添加以下样式

  .box1 {
    position: relative;
    z-index: 1
  }
  .innerBox {
    z-index: 99;
  }
  .box2 {
    z-index: 2;
  }

展示效果如下: 微信截图_20210315134545.png 我们可以看到innerBox虽然层级比box2高, 但是没有覆盖掉box2, 这是因为innerBox的父级box1拉平了innerBox的层级,box1的层级只有1,它的子元素只能在层级1的环境下进行提升,但是永远到达不了2,好比1.99 <<< 2, 这就是为什么我们z-index: 99无法覆盖z-index:1。

解决拉平层级

思路:

  1. 处于层叠上下文,能够使用z-index
  2. 父级不会影响到子级

解决方案: isolation: isolate会创建一个层叠上下文,并且它不会影响到子级元素

结束语

关注我,每天更新一篇知识

添加我微信号: IAmFineThanksMartin,进前端群讨论!