zIndex(涉及层叠上下文)
在日常工作中,我们经常使用 z-index 配合 position 属性来控制元素的遮盖顺序。
z-index 值越大,所属元素越靠上
<style>
.header {
position: relative;
z-index: 2;
}
.main {
position: relative;
z-index: 1;
}
.tooltip {
position: absolute;
z-index: 999999;
}
</style>
<div class="header">Welcome!</div>
<div class="main">
<div class="tooltip">Tooltip</div>
</div>
已经给 Tooltip 一个很大的 z-index 了,并且所有元素都已经具备 position:relative/absolute 了,为什么 Tooltip 被我们的 header 挡住了?
每个元素就是一层,每个具有 position 和 z-index 的元素会创建一个层叠上下文,层叠上下文就是元素的组,当我们给一个元素设置 z-index 的时候,它只会和同组的元素比较值
而回到 CSS 来,我们就非常好类比了。 默认情况下,HTML 中 html 标签就是最初的层叠上下文,包含所有的元素,而我们在其中嵌套创建了新的层叠上下文。创建层叠上下文的方式多种多样,但最普遍的就是我们的 position+z-index。
如果一个元素没有创建层叠上下文(不在任何层叠上下文中),那么它的优先级低于一切带有层叠上下文的 同级元素。
回到我们刚才的例子:
可以梳理出来层叠上下文是这样的
- html
- div.header[z-index=2]
- div.main[z-index=1]
- div.tooltip[z-index=999999]
用semver
的方式思考。tooltip 的 z-index 可以看做版本 1.999999,而 header 的版本是 2。无论小版本号多么庞大,那也永远比大版本号要小。所以 1.999999<2
,tooltip 在下方。
所以怎么修复就非常显而易见了:一种方式是不给 main 设置 z-index,让其退化为普通元素,普通元素默认层级较低
<style>
.header {
position: relative;
z-index: 2;
}
.main {
position: relative;
// No more z-index here!
// z-index: 1;
}
.tooltip {
position: absolute;
z-index: 999999;
}
</style>
二是将 tooltip 提升,渲染到 body 中, tootip 外不需要 main 包裹
- html
- div.header[z-index=2]
- div.tooltip[z-index=999999]
我们无需关心DOM上的层级关系,浏览器渲染时只关心层叠上下文。
- 层叠上下文可以包含在其他层叠上下文中,并且一起创建一个层叠上下文的层级。
- 每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
- 每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层 叠。
文档中新的层叠上下文由满足以下任意一个条件的元素形成:
- 文档根元素(<html>)
- position 值为 absolute或 relative且 z-index 值不为 auto 的元素
- position 值为 fixed或 sticky的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持)
- flex 容器的子元素,且 z-index 值不为 auto
- grid容器的子元素,且 z-index 值不为 auto
- opacity 属性值小于 1 的元素(参见 the specification for opacity)
- mix-blend-mode 属性值不为 normal 的元素
- 以下任意属性值不为 none 的元素:
- transform
- filter
- backdrop-filter
- perspective
- clip-path
- mask / mask-image / mask-border
- isolation 属性值为 isolate 的元素
- will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章)
- contain 属性值为 layout、paint 或包含它们其中之一的合成值(比如 contain: strict、contain: content)的元素。
层叠顺序
.first{
position: relative;
}
.second{
margin-top:-15px;
background-color: orangered;
}
first 在 second 上方
如果层叠上下文元素不注明 z-index 数值,则其层叠顺序是 z-index:auto,可看成 z-index:0 级别。这就是为什么定位元素会覆盖在普通元素上
—在定位后 z-index 已经被认为生效了,虽然没有创建新的层叠上下文,但是在上一级的比较中已经占了上风。
但如果同级元素拥有相同的 z-index,这时候遵循栈的思想。