涉及堆叠,其实就是网页的 z 轴。

写在前面的话

我们都知道 浮动元素 和 绝对定位元素会脱离文档流,不占文档空间,浮于文档内容之上,这就涉及到一个深度方向的排序问题。

处于同一层叠上下文的元素根据自身的层叠水平和层叠顺序规则来决定它在用户眼前的显示顺序。

堆叠顺序 8层

注意 下面是在同一堆叠上下文中的元素的堆叠顺序。在后面的知识我们可以知道如何产生堆叠上下文。

具体规则

  • 父 div 为非定位元素时,父元素及其子元素都处于 html 创建的堆叠上下文。
    0 z-index: 负值
  1. background (背景色原来会延伸到 border 处)
  2. border
  3. 子块级元素
  4. 子浮动元素(及内部文字)
  5. 子内联 元素(inline、inline-block)
  6. 子定位元素:z-index: 0 (z-index: auto;)
  7. 子定位元素z-index: 正值
  • 父 div 为非定位元素时 (position 非 static)产生新的堆叠上下文
  1. background (背景色原来会延伸到 border 处)
  2. border
  3. 子定位元素:z-index: 负值
  4. 子块级元素
  5. 子浮动元素(及内部文字)
  6. 子内联 元素(inline、inline-block)
  7. 子定位元素:z-index: 0 (z-index: auto;)
  8. 子定位元素z-index: 正值

如果是兄弟元素重叠,那么后面的盖在前面的身上。

上面的堆叠顺序可以设计实验去验证,验证方法才是重点,设计实验是CSS很核心的技巧。

不要将层叠水平和CSS的z-index属性混为一谈。没错,某些情况下z-index确实可以影响层叠水平,但是,只限于定位元素(position 属性值非 static)以及flex盒子的 flex item元素;而所有的元素都存在层叠水平。

层叠顺序验证

  • 父 div 内联元素/文本 > border > background code

堆叠上下文 - 图1

  • 父 div 内联元素/文本 > 子 div 元素 > border > background ,子 div 内联文本/元素 与 父 div 内联元素/文本 优先级相同,后来者居上。code

堆叠上下文 - 图2

堆叠上下文(The Stacking context)

参考MDN

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

可以理解为堆叠作用域。跟 BFC 一样,我们只知道当元素设置一些属性后,在该元素的位置上会产生堆叠上下文,但并不知道堆叠上下文是什么,但是打个比喻就很好理解,堆叠上下文就像一个公司的部门一样。如果移动两个优先级相同的堆叠上下文重合,则后者整体(包括里面的所有元素内容)覆盖前者。理解了堆叠上下文,就能理解在写CSS时为什么那个元素出现在最前面,而其他元素就被压在下面。

  1. 根元素 (HTML)
  2. z-index 值不为 “auto”的 绝对/相对定位
  3. 一个 z-index 值不为 “auto”的 flex 项目 (flex item),即:父元素 display: flex|inline-flex,
  4. position: fixed
  5. opacity 属性值小于 1 的元素(参考 the specification for opacity),
  6. transform 属性值不为 “none”的元素,
  7. mix-blend-mode 属性值不为 “normal”的元素,
  8. filter值不为“none”的元素,
  9. perspective值不为“none”的元素,
  10. isolation 属性被设置为 “isolate”的元素,
  11. 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值(参考 这篇文章)
  12. -webkit-overflow-scrolling 属性被设置 “touch”的元素

上面介绍的会产生新的堆叠上下文的属性中,我只见过前6种。

同一堆叠上下文中的元素有堆叠优先级规则(上面介绍了),而不同的堆叠上下文之间也有堆叠优先级。一个堆叠上下文可以理解为一个公司的部门。在整个文档中,根元素 (html) 会创建一个堆叠上下文,其子元素及子元素的后代都处在这个堆叠上下文中,堆叠的子元素显示顺序按堆叠顺序确定,此时根元素就是一个公司。根元素 (html) 的一些子元素通过设置某些属性会创建新的堆叠上下文,从而这些子元素的后代不在处于根元素创建的上下文中,这些子元素的后代将处于子元素刚刚创建的新的堆叠上下文中,这就好比公司创建了一些部门,部门的成员归部门主管管了,而不再直接归公司总经理管,总经理只用管部门主管就行了。同级子元素创建的这些新的堆叠上下文之间 也存在着堆叠优先级。当它们堆在一起时,优先级高的会覆盖优先级低,优先级相同的后面会覆盖前面。新的堆叠上下文之间 也存在着堆叠优先级,就像一个公司各个部门之间存在等级高低,一个部门的各个员工之间也存在等级高低。等级高的部门,其内部所有员工等级都比 等级低的部门内部员工等级 高

判断一个题:

z-index 为 9999 的绝对定位元素,一定在 z-index 为 0 的相对定位的元素上面吗?

答案是 不一定,只有当这两个元素处于通过一个堆叠上下文中才成立,否则还得比较它们处于的堆叠上下文的优先级高低。如:优先级低的堆叠上下文,其内部z-index 为 9999 的绝对定位元素,一定在优先级高的堆叠上下文中 z-index 为 0 的相对定位的元素 下面

层叠黄金准则

当元素发生层叠的时候,其覆盖关系遵循下面2个准则:

  1. 谁大谁上:当具有明显的层叠水平标示的时候,如识别的z-indx值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。通俗讲就是官大的压死官小的。
  2. 后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在DOM流中处于后面的元素会覆盖前面的元素。

参考

参考:张鑫旭