层叠上下文
什么是层叠上下文?
在CSS中,每个盒子的位置其实都是三维的。除了平面的X轴和Y轴之外,盒子还会沿着“Z轴”(垂直屏幕靠近用户方向)一个一个地往上堆叠,亦即产生了视觉上的重叠效果。看一下标准文档中给出的示意图:
这有个不太正确的类比,但也许能帮助你理解它们:层叠上下文就像JS中的执行上下文,内部维护了一些函数(元素盒子),不同函数在调用过程中形成了一个调用栈。元素盒子则是在定义时根据不同的定义方式获得了各自的层叠等级,它们按照层叠等级的高低也形成了一个栈,栈顶离用户最近。
层叠上下文分两种,一种是根元素<body>
自动创建的根层叠上下文(root stacking context),另一种是其他元素创建的本地层叠上下文( local stacking contexts)。每个盒子都必属于某个层叠上下文,但不是每个盒子都能创建层叠上下文。下面将整理创建层叠上下文的各种方式。
如何创建层叠上下文?
当一个元素创建了层叠上下文,此时它和两个上下文有关:一个是它所处的当前层叠上下文,另一个是新层叠上下文。新层叠上下文属于当前层叠上下文的一部分。
创建层叠上下文的方法有:
- 前面提到的根元素
<body>
自动创建根层叠上下文 z-index:auto
和z-index:0
的定位元素For those with ‘z-index: auto’, treat the element as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context should be considered part of the parent stacking context, not this new one.
对于z-index:auto
的定位元素,它的定位后代,以及能够创建层叠上下文的后代,都属于当前上下文。所以可认为 z-index:auto
元素并没有创建层叠上下文,而不是像文档所说的”treat the element as if it created a new stacking context”。
For those with ‘z-index: 0’ treat the stacking context generated atomically.
z-index:0
的定位元素自动创建层叠上下文。它的后代元素属于新创建的层叠上下,与z-index:0
定位元素所在的层叠上下文中的其他元素无关。
- 元素的
opactity
属性值不为1
。 - 元素的
transform
属性值不为none
。 - 元素的
filter
属性值不为1
。 - 当父元素是
display:flex|inline-flex
,后代元素的z-index
不为auto
层叠等级
什么是层叠等级?
层叠上下文中可以包含多个元素盒子。每个盒子都有一个层叠等级(等级可以为负),层叠等级按大小排列形成了第三个轴——“Z轴”,垂直屏幕向用户延申增大。
需要注意的时层叠等级仅在当前层叠上下文中才有排序意义。创建当前层叠上下文的元素,相对再上一层的层叠上下文而言也有层叠等级。这两个层叠上下文中的层叠等级互不干扰。
同级的不一定是兄弟盒子,也可以是父子盒子;兄弟盒子也不一定等级相等;当等级相同时按 dom 树顺序从下到上堆叠。
有哪些层叠等级?
在同一个层叠上下文中,会按照下面给出顺序逐层往上堆叠。当元素创建了新的层叠上下文,它会在其层叠作用域中从头再按顺序堆叠后代。
层叠等级顺序从低到高排列如下:
- background-color
- background-image
- border
- z-index 为负数
- 块级普通元素
- float盒子
- inline和inline-block盒子
- 等位元素
- 不依赖
z-index
的创建层叠上下文元素 - z-index >= 0 的元素
1~3指的是创建当前层叠上下文的元素的背景和边框。这是一个易错点:当比较层叠等级时,往往会把dom树结构上的父元素背景视为一个层叠等级,但是父元素并不是创建当前层叠上下文的元素。
正确做法是,首先确定创建当前层叠上下文的元素是什么,然后不要受dom结构的影响,按照上面给出顺序排列元素等级。这些元素中有些能够创建新的层叠上下文,这可视为一个断层,新层叠上下文中的元素先跳过,等排列完当前层叠上下文的所有元素,再去排列子层叠上下文的元素。
🌵最后
- 本文的例子中参考了张鑫旭前辈《深入理解CSS中的层叠上下文和层叠顺序》一文,致谢
- 这里📖 是层叠上下文的标准文档,致敬