重新理解z-index

一,前言

今天遇到一个布局兼容问题,调试了一番,发现z-index的表现和自己的认知不相符,才知道自己对z-index的认知有错误,于是写篇文章总结下这个z-index的具体使用。有基础的朋友可以直接看第四节。

二,标准文档流

在了解z-index之前,需要先知道标准文档流。

标准文档流其实是浏览器渲染页面的一个规则:所有的页面元素,都要按照它在HTML文档中出现的先后顺序,依次在浏览器中,从左上角开始,从上到下,从左到右的顺序依次显示。

具体的表现为:

2.1,块级元素:

有以下的几个特征:

 1.单独的占一行
 2.可以设置宽、高
 3.如果不设置宽度,他将默认占满父盒子的宽度

2.2,行内元素:

 1.与其他元素自动的并排在一行上
 2.不能设置它的宽和高,它的宽和高就是内容的宽和高

2.3,块级元素和行内元素可以相互转换:

 display:block
 display:inline

三,position

常见的使元素脱离文档流的手段有:浮动和定位。

之所以讲这个,是因为只有脱离了文档流,才有z-index来设置元素的层叠等级。

浮动好理解,定位主要是position的几个属性值:

通常情况下, position 有以下几个取值。具体如下:

取值 含义 说明
static 静态定位 对象遵循标准文档流,toprightbottomleft 等属性失效。
relative 相对定位 对象遵循标准文档流中,依赖toprightbottomleft 等属性相对于该对象在标准文档流中的位置进行偏移,同时可通过 z-index 定义层叠关系。
absolute 绝对定位 对象脱离标准文档流,使用 toprightbottomleft 等属性进行绝对定位(相对于 static 定位以外的第一个父元素进行绝对定位) ,以及可通过 z-index 定义层叠关系。
fixed 固定定位 对象脱离标准文档流,使用 toprightbottomleft 等属性进行绝对定位(相对于浏览器窗口进行绝对定位)同时可通过 z-index 定义层叠关系。
sticky 粘性定位 可以说是相对定位 relative 和固定定位 fixed 的结合。元素固定的相对偏移是相对于离它最近的具有滚动框的祖先元素,如果祖先元素都不可以滚动,那么是相对于 viewport 来计算元素的偏移量。

这些内容,网上很多文章都有,不再赘述,本文主要讲解z-index的规则,不忘初心。

四,z-index的层叠上下文理解

z-index应该这样理解:每一个层叠上下文就是一层楼,而该楼层的z-index就是楼梯。1楼层的楼梯值再大,也不可能比2层楼高。

于是我们首先要理解一个层叠上下文的生成条件:

1,根元素html ;
2,绝对定位 absolute 或相对定位 relative 且 z-index 值不为 auto ;
3,一个 flex 项目,且 z-index 值不为 auto ,也就是父元素 display: flex|inline-flex ;
4,元素的 opacity 属性值小于 1 ;
5,元素的 transform 属性值不为 none ;
6,元素的 mix-blend-mode 属性值不为 normal ;
7,元素的 isolation 属性被设置为 isolate ;
8,在 mobile WebKit 和 Chrome 22+ 内核的浏览器中,position: fixed 时总是会创建一个新的层叠上下文, 即使 z-index 的值是 auto ;
元素的 -webkit-overflow-scrolling 属性被设置 touch 。

后面几个比较少用暂且不谈,本文主要讲前几个。需要理清几个名词概念:

层叠上下文:对应本节中所说:生成的一个层叠上下文(一个楼层)
层叠等级:一个层叠上下文中的元素层叠规则:七层层叠规则
层叠上下文层级;每个层叠上下文之间是有级别的,低级别的无论z-index多大都无法突破高级别的层叠上下文。各个层叠上下文之间,用层级来描述(有的文章还是用层叠等级,这样容易混乱,所以我换种说法)

五,z-index的层叠等级

理解了层叠上下文还不够,因为每层层级上下文内还分为七个层叠等级。具体如下图:

请添加图片描述

如下代码,就能体现出这七层结构:

<!DOCTYPE html>
<html lang="en">
<body>
  <style>
    body{
      
      
      height: 100vh;
      background: pink;
    }
    /* 新创建一个层叠上下文 */
    .box{
      
      
      height: 350px;
      background: greenyellow;
      position: relative;
      z-index:1;
    }
    .total{
      
      
      height: 100px;
      width: 300px;
      text-align: center;
      position: absolute;
    }
    .first-item{
      
      
      background: yellow;
      top: 10px;
      left:10px;
      z-index: -1;
    }
    .second-item{
      
      
      background: blueviolet;
      display: block;
      top: 40px;
      left:40px;
    }
    .third-item{
      
      
      background: red;
      float: left;
      top: 70px;
      left:70px;
    }
    .fourth-item{
      
      
      background: blue;
      display: inline;
      top: 100px;
      left:100px;
    }
    .five-item{
      
      
      background: rgb(18, 248, 217);
      top: 130px;
      left:130px;
      z-index: auto;
    }
    .six-item{
      
      
      background: rgb(248, 83, 18);
      top: 160px;
      left:160px;
      z-index: 1;
    }
  </style>
  <div class="box">
    <div class="first-item total">z-index小于0 </div>
    <div class="second-item total">block块级盒子</div>
    <div class="third-item total">float浮动盒子</div>
    <div class="fourth-item total">inline/inline-block水平盒子</div>
    <div class="five-item total">z-index:auto或0或不设置</div>
    <div class="six-item total">z-index大于0</div>
  </div>
</body>
</html>

实现的效果和七层结构如出一辙:

请添加图片描述

如上文第四节创建层叠上下文的知识可知,这里html默认会创建一个基础的层叠上下文。为了避免它的影响,我这里让box再创建一个层叠上下文(有定位且有z-index)。

于是这六个子元素和自身的background/border其实都在这个box的层叠上下文中,就得遵守同一层叠上下文的七层层叠等级规则。

六,层叠上下文层级和dom结构关系

首先需要明确的一点是层叠上下文层级和dom结构没有明确的映射关系。但层叠上下文层级又基于dom结构生成。

主要是因为层叠上下文支持嵌套,在一个层叠上下文中还可以创造新的层叠上下文。但当未创建新的层叠上下文时,不管dom结构是不是父子关系,都是在同一层叠上下文之间,用七层层叠等级规则执行判断。

这里将上文的代码修改为:

<!DOCTYPE html>
<html lang="en">
<body>
  <style>
    body{
      
      
      height: 100vh;
      background: pink;
    }
    /* 新创建一个层叠上下文 */
    .box{
      
      
      height: 350px;
      background: greenyellow;
      position: relative;
      z-index:1;
    }
    .total{
      
      
      height: 100px;
      width: 300px;
      text-align: center;
      position: absolute;
    }
    .first-item{
      
      
      background: yellow;
      top: 10px;
      left:10px;
    }
    .second-item{
      
      
      background: blueviolet;
      display: block;
      top: 50px;
      left:40px;
      z-index: 1;
    }
    .a-1{
      
      
      background: red;
      height: 20px;
      position:absolute;
      left: 200px;
      top:30px;
      z-index: 5;
    }
    .a-2{
      
      
      background: rgb(229, 20, 236);
      height: 20px;
      position: absolute;
      z-index: -1;
      right: -20px;
      top: 27px;
    }

  </style>
  <div class="box">
    <div class="first-item total">
      <div class="a-1">a-1</div>
      <div class="a-2">a-2</div>
    </div>
    <div class="second-item total"></div>
  </div>
</body>
</html>

实现的效果:

请添加图片描述

就像这里,box创建了一个新的层叠上下文,又因为它具备子元素first-item和second-item,所以这两个元素必然是在同一个层叠上下文(box创建的)中。

而second-item不再有子元素,不用继续考虑,接下来看first-item。

因为first-item并没有创建新的层叠上下文(虽然有定位,但z-index未设置),则它的子元素也和它一样在当前box创建的层叠上下文中

也就是说,first-item和second-item,a-1以及a-2这四者是在同一个层级上下文中进行堆叠,即使a-1和a-2是first-item的子元素。

于是根据七层层叠规则得到:

box:创建该层叠上下文,它的background在最下面(草绿色)
first-item:block块级盒子(黄色)
second-item:z-index=1(紫色)
a-1:z-index=5(红色)
a-2:z-index=-1(粉色)

这个和上图中结果一致。这就是为啥说:**dom结构和层叠上下文没有严格的映射关系。**并不是一层dom就生成一个层叠上下文。

另外,**层叠上下文层级又基于dom结构生成。**意思就是低层级的层叠上下文,无论内部元素的z-index多大,是无论如何无法盖在高层级别元素上方的。

<!DOCTYPE html>
<html lang="en">
<body>
  <style>
    body{
      
      
      height: 100vh;
      background: pink;
    }
    /* 新创建一个层叠上下文 */
    .box{
      
      
      height: 350px;
      background: greenyellow;
      position: relative;
      z-index:1;
    }
    .total{
      
      
      height: 100px;
      width: 300px;
      text-align: center;
      position: absolute;
    }
    .first-item{
      
      
      background: yellow;
      top: 10px;
      left:10px;
      z-index: 1;
    }
    .second-item{
      
      
      background: blueviolet;
      display: block;
      top: 50px;
      left:40px;
      z-index: 2;
    }
    .a-1{
      
      
      background: red;
      height: 20px;
      position:absolute;
      left: 200px;
      top:30px;
      z-index: 5;
    }
    .a-2{
      
      
      background: rgb(229, 20, 236);
      height: 20px;
      position: absolute;
      z-index: -100;
      right: -20px;
      top: 27px;
    }
  </style>
  <div class="box">
    <div class="first-item total">
      <div class="a-1 total">a-1</div>
      <div class="a-2 total">a-2</div>
    </div>
    <div class="second-item total"></div>
  </div>
</body>
</html>

对应实现的效果和层叠上下文层级关系如下图,first-item的层级比second-item低,比box高,因此,first-item中的元素无论z-index设置多高,都无法超过second-item的内容。无论z-index设置多低,都无法低于box(草绿色),甚至无法低于创建该层叠上下文的背景色(该层叠上下文中层叠等级最低,下图黄色)。

请添加图片描述

七,判断元素层叠顺序的套路

理解了层叠上下文,层叠等级,层叠上下文层级三者的关系,就可以用这个来判断两元素的遮盖情况:

1,看两个元素所在的层叠上下文层级。高层元素必然遮盖低层元素。
2,若在同一层叠上下文层级,也就是在同一个层叠上下文中,就需要看七层层叠等级。谁高谁在上面
3,如果都一样,后写的盖住之前写的。

八,案例练习

8.1,多层dom结构,但实际是同一层级上下文的情况

<!DOCTYPE html>
<html lang="en">
<body>
  <style>
    body{
      
      
      height: 100vh;
      background: pink;
    }
    /* 新创建一个层叠上下文 */
    .box{
      
      
      height: 350px;
      background: greenyellow;
      position: relative;
      z-index:1;
    }
    .total{
      
      
      height: 100px;
      width: 300px;
      position: absolute;
    }
    .first-item{
      
      
      background: yellow;
      top: 10px;
      left:10px;
    }
    .a-1{
      
      
      width: 300px;
      height: 100px;
      background: green;
      float: left;
      top: 10px;
      left: 10px;
      position: absolute;
    }
    .b-2{
      
      
      width: 300px;
      height: 100px;
      background: blue;
      position: absolute;
      top: 40px;
      left: 20px;
      z-index: 100;
    }
    .second-item{
      
      
      background: orange;
      display: block;
      top: 30px;
      left:50px;
      z-index: 2;
    }
  </style>
  <div class="box">
    <div class="first-item total">
      <div class="a-1">float绿色</div>
      <div class="a-2">
        <div class="b-2">100蓝色</div>
      </div>
    </div>
    <div class="second-item total">2橙色</div>
  </div>
</body>
</html>

生成的效果如下图,因为first-item 并没有生成新的层叠上下文,所以first-item ,second-item,a-1,a-2,b-2这几个元素都是在同一个层叠上下文中,直接利用七个层叠等级规则判断就好:

请添加图片描述

8.2,多层dom结构,多个层叠上下文层级的情况

给上文的first-item增加一个样式:

.first-item{
    
    
    z-index: 1;
}

效果变成:

请添加图片描述

这是因为first-item也创建一个层叠上下文,和second-item创建的并列,并且上下文层级低于second-item。于是即使b-2的z-index:100也无法高于second-item。

九,总结

对于z-index的使用规律,MDN实际上就简单一句话:”z-index越大则越上层,有爹则拼爹“。

实际上,则是:

1,同一个层叠上下文中,z-index越大则越上层。
2,不同层级上下文,则层级越高越上层。
3,层级等级和层叠等级相同的,则后来的覆盖之前的。

其实很多人误解的一点就是以为dom结构和层叠上下文层级并没有严格的映射关系。a元素的n层孙元素,有可能和a是在同一个层叠上下文中的。

猜你喜欢

转载自blog.csdn.net/weixin_42349568/article/details/131561051