阅读 19

层叠式上下文

什么是层叠式上下文

MDN 上对层叠式上下文的解释为:

The stacking context is a three-dimensional conceptualization of HTML elements along imaginary z-axis relative to the user, who is assumed to be facing the viewport or the webpage. HTML elements occupy this space in priority order based on element attributes.

层叠上下文(stacking context)是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

简单来说,正常情况下,网页上的内容都是一个个正常的排列,然而由于页面内容并没有一个垂直方向的视角可以查看,所以,当页面上的内容发生重叠的时候,一定会有一个先后的顺序来呈现,而层叠式上下文就是解决这个问题的。

CSS 2.1 规范中,每个盒模型的位置是三维的,一般情况下我们只能感知到页面上左右方向和上下方向分别对应的 X 轴和 Y 轴,感觉不到垂直于电脑屏幕的 Z 轴,如下图所示:

层叠顺序

前面我们讲了元素发生重叠时要有一个先后的顺序来排列,那么不同的元素之间就会有一个等级的比较(就是谁等级高谁在前面),那么怎么去判定的等级高呢,我们一下子就想到了 z-index 属性,的确,很多时候,z-index 可以影响元素的层叠等级,但是 z-index 只能在定位的元素上起作用,而层叠等级是在每个元素中都存在的。

每个元素的层叠顺序是由元素当前所属的层叠式上下文和元素本身的层叠等级来决定的。也就是说比较元素的层叠顺序,必须是在同一个层叠式上下文中进行比较,否则将毫无意义,具体的规则如下:

  1. 在同一个层叠式上下文中,层叠级别大的显示在上面,级别小的显示在下面。
  2. 在同一个层叠式上下文中,如果层叠级别相同,则按照它们在文档流中的顺序,写在后面的将覆盖前面的。
  3. 在不同的层叠式上下文中,元素的显示顺序依据祖先的层叠级别来决定,与自身的层叠级别无关。

在 CSS2.1(不考虑CSS3)时期,层叠顺序遵循下面的图中所示的规则:

上面需要注意的是:

  1. 位于最底层的 border/background 指的是层叠上下文元素的边框和背景色。
  2. 单纯从层叠水平上看, z-index:0 和 z-index:auto 是属于同一等级的,但是两者是有本质区别的。

如何形成层叠式上下文

前面讲了层叠顺序要在同一个层叠式上下文中进行比较,那么如何形成一个层叠式上下文呢? 以下是 MDN 上总结的形成层叠式上下文的条件:

  1. 根元素 (HTML),形成一个根级的上下文。
  2. 定位的元素(绝对/相对定位/fixed定位),z-index 值不为 auto 时。
  3. css3 中的一些属性:
    • z-index 值不为 auto 的 flex 项(父元素display:flex|inline-flex)。
    • 元素的 opacity 值不是1;
    • 元素的 transform 值 不是 none;
    • mix-blend-mode 属性值不为 normal 的元素;
    • filter值不为 none 的元素;
    • perspective值不为 none 的元素;
    • isolation 属性被设置为 isolate 的元素,
    • 在 will-change 中指定了任意 CSS 属性;
    • -webkit-overflow-scrolling 属性被设置 touch 的元素;

demo 时刻

定位与 z-index 值

<div class="box1">
  <p class="a">a盒子</p>
  <p class="b">b盒子</p>
</div>
<div class="box2">
  <p class="c">c盒子</p>
</div>
复制代码
p {
  position: absolute;
  font-size: 20px; 
  width: 100px;
  height: 100px;
}
.a {
  background-color: aqua; 
}
.b {
  background-color: pink; 
  top: 40px;  
  left: 40px;  
}
.c {
  background-color: beige;
  top: 80px;  
  left: 80px;  
}
复制代码

按上面代码,此时 a、b、c 三个盒子都发生了定位,但是它们的父盒子都没形成层叠式上下文,因此会按照文档流的顺序发生层叠,结果如下图:

evernotecid://7F04FEFC-BAE7-46E8-9645-3E736A89ACEB/appyinxiangcom/2486197/ENResource/p1178

接下来我们进行一下改动,给 a、b、c 三个盒子分别加上 z-index 值,

.a {
  z-index: 3;  
}
.b {
  z-index: 2;  
}
.c {
  z-index: 1;  
}

复制代码

这时候,三个盒子自身都形成了层叠式上下文,但是它们的父盒子依旧没有形成层叠式上下文,所以它们是同属于一个层叠式上下文中,也就是根级,这时候它们的排列会按照各自的层叠等级进行排列,也就是 z-index 值大的在上面如下图所示:

接下来再进行一下改进,给它们的父元素分别加上以下属性:

div {
  position: relative;
}
.box1 {
  z-index: 1
}
.box2 {
  z-index: 2
}
复制代码

此时呢,两个 div 父元素都形成了一个层叠式上下文,那么 a、b 在同一个上下文中,按照自身的层叠等级进行排列,而 它们和 c 元素则处于不同的层叠上下午呢中, 所以根据父级的 z-index 大小来确定层级:

层叠顺序 demo

根据前面层叠顺序图中所示,我们创建了以下demo:

.one{
      background: #4f6fc1;
      margin-left: 100px;
}
.two{
      float: left;
      background: #51cd8d;
      margin-top: -100px;
}
.three{
     display: inline-block;
     background: #9cd262;
     margin-left: -100px;
}
复制代码
<div class="one">one —— 块级元素</div>
<div class="two">two —— 浮动元素</div>
<div class="three">three —— inline/inline-block 元素</div>
复制代码

上图可以看出,层级关系为:行内块盒子(inline-block)> 浮动元素 > 块级元素。因此如果我们想要盖住某一条线的话,不一定非得要用 display: relative,可以直接用 display: inline-block 就可以了。

接下来我们再加入一个 z-idnex 为负值的盒子

.four{
  position: absolute;
  z-index: -1;
  background: #8874c1;
}
复制代码
<div class="four">four —— z-index为负值</div>
<div class="one">one —— 块级元素</div>
<div class="two">two —— 浮动元素</div>
<div class="three">three —— inline/inline-block 元素</div>
复制代码

可以看出此时,z-idnex 为负值的盒子层级最低,跟前面的层级图中所表示的相符合。

最后,我们再加上 z-idnex 为 0 和正值的盒子。

.five{
     position: absolute;
     background: #d9ac4c;
     margin-top: -130px;
     margin-left: 50px;
}
.six{
    position: absolute;
    z-index: 1;
    background: #d93953;
    margin-top: -50px;
    margin-left: 150px;
}
复制代码
 <div class="five">five —— z-index:auto/z-index:0</div>
 <div class="six">six —— z-index为正值</div>
复制代码

此时,5号盒子 z-index 值为 auto,但是却和 z-index 值为 0 一样的等级,但是两者本质上却是不同的,前面说过,z-index 值为 0 是创建了一个自己的层叠式上下文的,而值为 auto 却没有。

最后前面介绍的几个 CSS3 的属性所在的层叠等级是和 z-index:auto/z-index:0 是处在同一等级的,感兴趣的可以试一下。

参考

张鑫旭-《深入理解CSS中的层叠上下文和层叠顺序》 MDN--The stacking context css层叠上下文【stacking context】和层叠顺序【stacking order】

关注下面的标签,发现更多相似文章
评论