层叠上下文
1. 概念
层叠上下文(stacking context) 是一个抽象概念,和 BFC 类似。可以理解为是一个体系块,这个块是独立的,在这个块内,定义了一系列的规则(层级等级 stacking level)来解释在发生堆叠时,图层的显示顺序。
2. 层叠等级
W3官方定义一共 7 层,以图层按从后到前的顺序绘制:
- 形成层叠上下文的元素的背景和边框
- the background and borders of the element forming the stacking context.
- 具有负的层叠等级(
z-index
)的子层叠上下文元素(负的越大越堆叠层级越低)
- the child stacking contexts with negative stack levels (most negative first).
- 流式布局,而且是 非行内元素、非定位元素的子元素
- the in-flow, non-inline-level, non-positioned descendants.
- 非定位元素的浮动元素
- the non-positioned floats.
- 流式布局,而且是 行内元素(包括 display:table 和 display:inline)、非定位元素的子元素。
- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
- 层叠等级为 0 的子层叠上下文或者子定位元素
- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
- 注:从个人理解,
z-index
为auto
也是这一层
- 正的层叠等级的子层叠上下文(正的越小越堆叠层级越低)
- the child stacking contexts with positive stack levels (least positive first).
用 css 样式来表示各个等级
/* 形成层叠上下文的元素的背景和边框 */
.level-1 {
position: relative;
width: 1000px;
height: 100px;
z-index: 1;
background-color: salmon;
}
/* 具有负的层叠等级(`z-index`)的子层叠上下文元素(负的越大越堆叠层级越低) */
.level-2 {
position: relative;
z-index: -1;
width: 900px;
height: 200px;
background-color: seagreen;
}
/* 流式布局,而且是 非行内元素、非定位元素的子元素 */
.level-3 {
width: 800px;
height: 300px;
background-color: slateblue;
}
/* 非定位元素的浮动元素 */
.level-4 {
float: left;
width: 700px;
height: 400px;
background-color: slategray;
}
/* 流式布局,而且是 行内元素(包括 display:table 和 display:inline)、非定位元素的子元素。 */
.level-5 {
display: inline-block;
width: 600px;
height: 700px;
background-color: springgreen;
}
/* 层叠等级为 0 的子层叠上下文或者子定位元素 */
.level-6 {
position: relative;
z-index: 0;
width: 500px;
height: 800px;
background-color: steelblue;
}
/* 正的层叠等级的子层叠上下文(正的越小越堆叠层级越低) */
.level-7 {
position: relative;
z-index: 1;
width: 400px;
height: 700px;
background-color: tan;
}
3. 创建层叠上下文
MDN中说明了,文档中的层叠上下文由满足以下任意一个条件的元素形成:
- 文档根元素(
<html>
); position
值为absolute
(绝对定位)或relative
(相对定位)且z-index
值不为auto
的元素;position
值为fixed
(固定定位)或sticky
(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);flex
容器的子元素,且z-index
值不为auto
;grid
容器的子元素,且z-index
值不为auto
;opacity
属性值小于 1 的元素;mix-blend-mode
属性值不为normal
的元素;- 以下任意属性值不为 none 的元素:
- transform
- filter
- perspective
- clip-path
- mask / mask-image / mask-border
isolation
属性值为isolate
的元素;-webkit-overflow-scrolling
属性值为touch
的元素;will-change
值设定了任一属性而该属性在non-initial
值时会创建层叠上下文的元素;contain
属性值为layout
、paint
或包含它们其中之一的合成值(比如contain: strict、contain: content
)的元素。
4. 在线演示
直接子元素
在一个层叠上下文中,直接子元素,按层叠等级显示
实时编辑器
function InStackingContext() { return ( // 这个容器无意义,只是为了给这个示例一个高度 <div style={{ width: 90, height: 90, }} > {/* stacking context */} <div style={{ position: 'relative', zIndex: 1, width: 90, height: 90, background: 'lightblue', }} > {/* level-6 */} <div style={{ position: 'relative', width: 30, height: 90, backgroundColor: 'blue', }} /> {/* level-3 */} <div style={{ width: 60, height: 30, backgroundColor: 'blueviolet', marginTop: -90, }} /> {/* level-2 */} <div style={{ position: 'relative', zIndex: -1, width: 60, height: 60, backgroundColor: 'gray', marginTop: -30, }} /> </div> </div> ) }
结果
Loading...
嵌套普通元素
在上面的层叠等级中可以看到,有些等级(如: level-3
, level-4
, level-5
)它是没有创建层叠上下文的,它在这里只是看起来好像在绘制的时候,创建了一个层叠上下文。
主要区别表现在:这些元素(指 level-3
, level-4
, level-5
)的后代是定位元素或者其他新的层叠上下文时
直接子元素没有创建层叠上下文,深度嵌套的
定位元素
或者新的层叠上下文
的元素,参与最近的堆叠上下文进行绘制
实时编辑器
function InStackingContext() { return ( // 这个容器无意义,只是为了给这个示例一个高度 <div style={{ width: 90, height: 90, }} > {/* stacking context */} <div style={{ position: 'relative', zIndex: 1, width: 60, height: 60, background: 'gray', }} /> {/* 普通元素 */} <div style={{ width: 90, height: 30, background: 'lightblue', marginTop: -60, }} > {/* stacking context */} <div style={{ position: 'relative', zIndex: 2, width: 30, height: 90, backgroundColor: 'blue', }} /> </div> </div> ) }
结果
Loading...
嵌套新的层叠上下文
直接子元素创建层叠上下文时,该元素及其后代元素,将作为一个整体,参与最近的堆叠上下文进行绘制
实时编辑器
function InStackingContext() { return ( // 这个容器无意义,只是为了给这个示例一个高度 <div style={{ width: 90, height: 90, }} > {/* stacking context */} <div style={{ position: 'relative', zIndex: 1, width: 60, height: 60, background: 'gray', }} /> {/* stacking context */} <div style={{ position: 'relative', zIndex: 0, width: 90, height: 30, background: 'lightblue', marginTop: -60, }} > {/* stacking context */} <div style={{ position: 'relative', zIndex: 2, width: 30, height: 90, backgroundColor: 'blue', }} /> </div> </div> ) }
结 果
Loading...
5. 总结
- 每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
- 每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠。
- 未创建层叠上下文的元素,其定位后代元素或者新的层叠上下文,会参与父级层叠上下文绘制
另外需要注意的是
position
为 absolute
或者 relative
,此时 z-index
默认为 auto
,它是不会创建层叠上下文的。
只有 z-index
为数字时才会创建层叠上下文。
虽然在一个层叠上下文中,两者的绘制顺序看起来是一致的,但一个创建层叠上下文,一个不会创建,还是有本质区别的。