CSS学习(16)层叠上下文

136 阅读9分钟

前言

  • 什么是层叠上下文,什么是层叠等级,什么是层叠顺序?

层叠上下文

在介绍层叠上下文之前,我们先了解一下HTML文档中的三维概念。

平时我们从设备终端看到的HTML文档都是一个平面的,事实上HTML文档中的为元素却是存在于三个维度中。除了大家熟悉的平面画布中的x轴和y轴,还有控制第三维度的z轴。

screenshot-20240717-150023.png

其中x轴通常用来表示水平位置,y轴来表示垂直位置,z轴表示屏幕内外方向上的位置。

对于x和y轴我们很易于理解,一个向右,一个向下。但对于z轴,理解起来就较为费力。在CSS中要确定沿着z轴排列元素,是表示的用户与屏幕的这条看不见的垂直线:

screenshot-20240717-150639.png

而这里我们要讨论的层叠上下文(stacking context),就是HTML中的一个三维的概念。如果一个元素含有层叠上下文,我们可以理解为这个元素在z轴上就“高人一等”,最终表现就是它离屏幕观察者更近。

听上去好像很不错的样子,我想让一个元素更加靠前,我就给它创建一个层叠上下文。

那么具体的创建方法有哪些呢?

  • HTML中的根元素HTML本身就具有层叠上下文,称为"根层叠上下文"。
  • position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index值不为 auto 的元素。
  • position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素。
  • CSS3中的新属性也可以产生层叠上下文。
<div class="one"></div>
<div class="two"></div>
div{
  width: 150px;
  height: 150px;
}
.one {
  background-color: red;
}

.two {
  background-color: blue;
  margin-top: -100px;
}

screenshot-20240717-153150.png

我们给one设置如下代码:

.one {
  background-color: red;
  position: relative;
  z-index: 1;
}

screenshot-20240717-153241.png

由于设置了定位和z-index属性,所以one就会创建了一个层叠上下文,在z轴上就"高人一等"。

层叠等级层叠顺序

层叠等级(stacking level)

层叠顺序(stacking order)

这两个概念都是用来描述在同一个层叠上下文中,元素在z轴上的显示顺序。

“层叠上下文”和“层叠等级”是一种概念,而这里的“层叠顺序”是一种规则。

层叠等级的高低规则是由层叠顺序来体现的。

在CSS2.1的年代(注意这里的前提),层叠顺序规则遵循下面这张图:

screenshot-20240717-154012.png

如果两个元素在同一个层叠上下文中,那么它们在z轴上的显示顺序就由它们的层叠等级来决定。

如果两个元素不在同一个层叠上下文中,那么此时就先比较他们所处的层叠上下文的层叠等级,也就是所谓的"从父"现象。

层叠上下文可以包含多个层叠上下文,层叠上下文内的层叠顺序是独立于外部的。

实战案例

在开始案例之前,先对上面的知识进行一下总结:

  1. 首先先看两个元素是否属于同一个层叠上下文中
  • 如果是,谁的层叠等级大,谁在上面(判断层叠等级大小参阅上面面的"层叠顺序"图)
  • 如果两个元素不在同一层叠上下文中,请先比较他们所处的层叠上下文的层叠等级。
  1. 两个元素层叠等级相同、层叠顺序相同时,在DOM结构中后面的元素层叠等级在前面元素之上。

案例一

<div class="one">
  <div class="child child1"></div>
</div>
<div class="two">
  <div class="child child2"></div>
</div>
div{
  width: 200px;
  height: 200px;
}
.one {
  background-color: red;
  position: relative;
  z-index: 1;
}
.two {
  background-color: blue;
  position: relative;
  z-index: 2;
}
.child {
  width: 100px;
  height: 100px;
  position: absolute;
  top: 200px;
  left: 200px;
}
.child1 {
  background-color: green;
  z-index: 99;
}
.child2 {
  top: 50px;
  background-color: yellow;
  z-index: 1;
}

效果

screenshot-20240717-175425.png

分析

  • 首先one和two都是层级上下文,并且处于同一个层级上下文,two的层级等级比one大;

  • 其次child1属于one这个层级上下文中,child2属于two这个层级上下文中,child1和child2不属于同一个层级上下文,先比较所属层级上下文的等级,由于上面分析的two的层级等级比one大,所以child2会在child1上面。

案例二

修改上述one和two的样式,将各自的z-index注释掉:

.one {
  background-color: red;
  position: relative;
  /* z-index: 1; */
}
.two {
  background-color: blue;
  position: relative;
  /* z-index: 2; */
}

效果

screenshot-20240717-184232.png

分析

由于one和two的z-index被注释掉了,所以one和two就不是层级上下文了,此时child1和child2属于同一个层级上下文(根元素HTML),在同一个层级上下文中,child1的层级等级比child2大,所以这时,child1会在child2上面。

案例三

修改上述one和two的样式,将两个的z-index设置为相同值:

.one {
  background-color: red;
  position: relative;
  z-index: 1;
}
.two {
  background-color: blue;
  position: relative;
  z-index: 1;
}

效果

screenshot-20240717-175425.png

分析

我们看到效果跟案例一一样,这是因为child1和child2的层级由one和two的层级决定,而one和two的层叠等级相同、层叠顺序相同,这时依据后来者居上的原则,two会在one上面,所以child2会在child1上面。

案例四

<div class="one">
  <div class="child"></div>
</div>
div{
  width: 200px;
  height: 200px;
}
.one {
  background-color: red;
  position: absolute;
}
.child {
  background-color: green;
  position: absolute;
  top: 50px;
  left: 50px;
  z-index: -1;
}

效果

screenshot-20240717-190746.png

分析

one 是普通元素,child的z-index为-1,小于0,one和child都属于根元素这个层级上下文,根据层叠顺序规则,z-index为负值的元素在块级盒子下面,所以child在one下面。

案例五

修改one的样式,增加z-index: 9999;

.one {
  background-color: red;
  position: absolute;
  z-index: 9999;
}

效果

screenshot-20240717-191856.png

分析

当one增加了z-index: 9999;,one就形成了一个层级上下文,此时child归属的层级上下文从根元素变成了one。而根据层叠顺序,background是处于最下层的,所以child显示在了最上面。

案例六

<div class="parent">
  parent
  <div class="child1">
    child1
  </div>
  <div class="child2">
    child2
    <div class="child2-1">
      child2-1
    </div>
    <div class="child2-2">
      child2-2
    </div>
  </div>
  </div>
</div>
.parent {
  width: 100px;
  height: 200px;
  background-color: red;
  position: absolute;
  z-index: 0;
}
.child1 {
  width: 100px;
  height: 200px;
  background-color: blue;
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 1;
}
.child2 {
  width: 100px;
  height: 200px;
  background-color: green;
  position: absolute;
  top: 40px;
  left: 40px;
  z-index: -1;
}
.child2-1 {
  width: 100px;
  height: 200px;
  background-color: yellow;
  position: absolute;
  top: 60px;
  left: 60px;
  z-index: 9999;
}
.child2-2 {
  width: 100px;
  height: 200px;
  background-color: pink;
  position: absolute;
  top: 80px;
  left: 80px;
  z-index: -9999;
}

效果

screenshot-20240717-193740.png

分析

根据案例案例五我们知道.child2-1和.child2-2在.child2上面,.child2-1和.child2-2在同一个层级上下文中,.child2-1的z-index大于.child2-2的z-index,所以.child2-1在.child2-2上面;

.child1 跟 .child2在同一个层级上下文中,.child1的z-index大于.child2的z-index,所以.child1在.child2上面;

根据案例案例五我们知道.child1 跟 .child2都在.parent上面;

所以最终效果是 .child1 -> .child2-1 -> .child2-2 -> -> .child2 -> .parent

CSS3属性对层叠上下文的影响

CSS3中出现了很多新属性,其中一些属性对层叠上下文也产生了很大的影响。如下:

  1. 父元素的display属性值为flex|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

例如

<div class="box">
  <div class="parent">
    parent
    <div class="child">child</div>
  </div>
</div>
.box {
  display: flex;
}
.parent {
  width: 200px;
  height: 100px;
  background: red;
  z-index: 1;
}
.child {
  width: 100px;
  height: 200px;
  background: blue;
  position: relative;
  z-index: -1;
}

效果

20240717-194501.gif

分析

由于父元素的display属性值为flex,子元素的z-index属性值不为auto,所以子元素为层叠上下文元素,所以child会在parent上面。

如果将父元素的display: flex;注释掉,那么.parent就不是层叠上下文元素,这时.child的z-index为-1,小于0,.child在.parent下面。

总结

  • 什么是层叠上下文,什么是层叠等级,什么是层叠顺序?

层叠上下文概念

在CSS2.1规范中,每个盒模型的位置是三维的,分别是平面画布上的X轴,Y轴以及表示层叠的Z轴。

一般情况下,元素在页面上沿X轴Y轴平铺,我们察觉不到它们在Z轴上的层叠关系。而一旦元素发生堆叠,这时就能发现某个元素可能覆盖了另一个元素或者被另一个元素覆盖。层叠上下文就是对这些 HTML 元素的一个三维构想。

层叠上下文触发条件

  • HTML中的根元素HTML本身就具有层叠上下文,称为"根层叠上下文"。
  • position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index值不为 auto 的元素。
  • position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素。
  • CSS3中的新属性也可以产生层叠上下文。

层叠等级

如果两个元素在同一个层叠上下文中,那么层叠等级越大的元素就越靠前。层叠等级是一个概念,层叠等级的大小可以根据层叠顺序来进行判断。

层叠顺序

层叠顺序表示元素发生层叠时按照特定的顺序规则在Z轴上垂直显示。

说简单一点就是当元素处于同一层叠上下文内时如何进行层叠判断,是一种规则。