css又叫层叠样式表,顾名思义就是一层层叠起来的,虽然在页面中呈现的效果的二维的,但实际是三维的。元素的层叠顺序是基于 z 轴的,并且永远不会有两个在 z 轴上重合的元素。判断元素在 z 轴上的堆叠顺序,不仅仅是直接比较两个元素的 z-index 值的大小,这个堆叠顺序实际由元素的层叠上下文、层叠等级共同决定。

层叠上下文(Stacking Context)

可以想象一个盒子,里面放了东西,这个盒子就代表着一个层叠上下文(盒子里面的东西的层叠关系由上下摆放的顺序决定)。 如果在这个盒子里面还有另外一个盒子,就代表着另一个层叠上下文(另外一个盒子里面东西的层叠关系也是由摆放的顺序决定)。 每一个网页都有一个默认的层叠上下文。 这个层叠上下文(桌子)的根源就是 <html>。 html 标签中的一切都被置于这个默认的层叠上下文的一个层叠层上(物品放在盒子里)。 当你给一个定位元素赋予了除 auto 外的 z-index 值时,你就创建了一个新的层叠上下文,其中有着独立于页面上其他层叠上下文和层叠层的层叠层。 这也就是为什么有时候我们的子元素设置了 z-index:9999 仍然可能会被其他元素覆盖,这很有可能是他的父元素不争气,排在了覆盖物的后面导致的。如下例所示:

  1. <div class="box1">我是配角</div>
  2. <div class="box2">
  3. <div class="son">我才是主角,我被父元素的层叠上下文束缚了</div>
  4. </div>
  5. <style>
  6. .box1 {
  7. position: absolute;
  8. z-index: 1;
  9. width: 200px;
  10. height: 200px;
  11. background: yellow;
  12. opacity: 0.7;
  13. }
  14. .box2 {
  15. width: 400px;
  16. height: 300px;
  17. position: absolute;
  18. z-index: 0;
  19. background: green;
  20. text-align: right;
  21. }
  22. .box2>.son {
  23. position: relative;
  24. z-index: 9999;
  25. }
  26. </style>

1.png

在层叠上下文中,其子元素按照上面解释的规则进行层叠。形成层叠上下文的方法有:

  • 根元素
  • position 值为 absolute 或 relative,且 z-index值不为 auto
  • position 值为 fixed 或 sticky
  • z-index 值不为 auto 的 flex 元素,即:父元素 display: flex 或 inline-flex
  • opacity 属性值小于 1 的元素
  • transform 属性值不为 none的元素
  • mix-blend-mode 属性值不为 normal 的元素
  • filter、 perspective、 clip-path、 mask、 mask-image、 mask-border、 motion-path 值不为none 的元素
  • perspective 值不为 none 的元素
  • isolation 属性被设置为 isolate 的元素
  • will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值
  • -webkit-overflow-scrolling属性被设置touch的元素

总结:

  • 层叠上下文可以包含在其他层叠上下文中,并且一起组建了一个有层级的层叠上下文
  • 每个层叠上下文完全独立于它的兄弟元素,当处理层叠时只考虑子元素,这里类似于BFC
  • 每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父级叠上下文中按顺序进行层叠

层叠等级 (Stacking Level)

层叠等级 (层叠水平, Stacking Level) 决定了同一个层叠上下文中元素在 z 轴上的显示顺序的概念

  • 普通元素的层叠等级优先由其所在的层叠上下文决定
  • 层叠等级的比较只有在同一个层叠上下文元素中才有意义
  • 在同一个层叠上下文中,层叠等级描述定义的是该层叠上下文中的元素在 Z 轴上的上下顺序

注意,层叠等级并不一定由 z-index 决定,只有定位元素的层叠等级才由 z-index 决定,其他类型元素的层叠等级由层叠顺序、他们在 HTML 中出现的顺序、他们的父级以上元素的层叠等级一同决定。

层叠顺序(Stacking Order)

2.png

在这个层叠顺序表中,我们可以注意到,在层叠上下文结界中,默认层级最高的是 inline/inline-block元素,层级最低的永远是 background 和 border,默认层级居中的是一些布局用的盒子,这也符合CSS设计的标准,以图文展示为主,其次是布局,最次儿的就是装饰性的 background 和 border 属性了。 除了上面提到的 CSS2.1 的标准,作者在 CSS 层叠领域总结了两条黄金准则,在元素发生层叠的时候,其覆盖关系遵循下面两条准则: (1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的 z-index 属性值,在同一个层叠上下文结界馁,层叠水平值大的那一个覆盖小的那一个。 (2)后来居上:当元素层叠水平一致的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。 结合这两条准则,就可以解释任何元素发生重叠时的显示顺序的问题了。如果下例所示:

<div class="father">
  <span class="inline">inline元素</span>
  <div class="float"></div>
  <div class="block"></div>
</div>

<style>
  .father {
    position: relative;
    background: rgb(255, 255, 0);
  }

  .block {
    background: rgb(255, 0, 0);
    width: 100px;
    height: 120px;
  }

  .float {
    float: left;
    background: rgb(0, 255, 255);
    width: 100px;
    height: 100px;
    margin-left: 50px;
  }

  .inline {
    margin-left: -100px;
    background: rgb(0, 255, 0);
  }
</style>

3.png
运用上图的逻辑,上面的题目就迎刃而解,inline-blcok 的 stacking level 比 float 要高,所以无论 DOM 的先后顺序都堆叠在上面。

参考