在 CSS
中,有一个属性可以显式控制 HTML
元素的堆叠顺序:z-index
。具有较高值的元素就会出现在顶部:
<style>
.box {
position: relative;
width: 50px;
height: 50px;
border: 3px solid;
background: silver;
}
.first.box {
z-index: 2;
background-color: peachpuff;
}
.second.box {
z-index: 1;
margin-top: -20px;
margin-left: 20px;
}
style>
<div class="first box">div>
<div class="second box">div>
因为.first.box
元素的z-index
值 比.second.box
的大,所以它堆叠在前面。如果我们删除z-index
属性,.first.box
就会处于.second.box
元素后面。
但是有时候z-index
更大也层级不一定生效。
<style>
body {
background: #eee;
}
header {
height: 60px;
line-height: 60px;
background: pink;
text-align: center;
position: relative;
z-index: 2;
}
main {
padding: 32px;
position: relative;
z-index: 1;
}
.tooltip {
top: -12px;
left: 0px;
right: 0px;
margin: 0 auto;
width: 90px;
text-align: center;
padding: 8px;
background: white;
box-shadow: 1px 2px 8px hsla(0deg, 0%, 0%, 0.25);
border-radius: 6px;
position: absolute;
z-index: 999999;
}
style>
<header>
Header
header>
<main>
<div class="tooltip">
A tooltip
div>
<p>contentp>
main>
从上图可以看到.tooltip
的z-index
值是比header
元素更大的,但是却处于header
元素之下,为了解释这种情况,我们需要了解堆叠上下文,这是一种晦涩但基本的 CSS 机制。在本文中,我们将探讨它们是什么、它们如何工作以及如何利用它们来发挥我们的优势。
我们使用photoshop
来距离说明层和组的概念。
我们的图像有 3 个独立的画布,像煎饼一样堆叠起来。最底层是一张猫的照片,上面有两层添加了一些的细节。通过堆叠这些层,我们最终得到了的图像如下:
而且还可以对图层进行分组:
就像文件夹中的文件一样,组允许我们对图层进行分段。在堆叠顺序方面,不允许图层在组之间“混合”:所有dog
的图层将出现在所有cat
的图层之上。
当我们导出合成时,我们根本看不到猫,因为它在狗后面:
CSS
的工作方式类似:元素被分组到堆叠上下文中。当我们给一个元素一个 z-index
时,该值仅与同一上下文中的其他元素进行比较。z-index
值不是全局的。
默认情况下,纯 HTML
文档将具有包含所有节点的单个堆叠上下文。但我们可以创建额外的上下文!
创建堆叠上下文的方法有很多,但以下是最常见的:
.element {
position: relative;
z-index: 1;
}
通过组合这两个声明,会触发一个秘密机制:创建一个堆栈上下文,围绕该元素及其所有子元素形成一个组。
那么对于一开始抛出的那个header
在.tooltip
上的问题我们就可以进行解析了。
我们创建的堆叠上下文为:
.tooltip
元素的 z-index
为 999999,但该值仅在
堆叠上下文中相关。.tooltip
元素只是显示在相邻
标签的上方而已。
同时,在父上下文中,
和
进行比较。因为
的z-index
较小,所以它显示在
下面。
那么如何解决呢,只需要在
中去除z-index
属性即可,这样就不会创建堆叠上下文,那么整体的结构层次为:
- 根上下文
-
-
创建堆叠上下文
我们已经了解了如何通过将相对或绝对定位与z-index
相结合来创建堆叠上下文,以下是其他一些方法:
- 设置
opacity
为小于1的值 - 设置
position
为fixed
或sticky
(这些值不需要 z-index
) - 在存在
display: flex
或者display: grid
属性的父容器中的子元素中添加一个z-index
属性 - 使用
transform
、filter
、clip-path
、 或perspective
will-change
值设置为opacity
或者transform
- 使用
isolation: isolate
显式地创建一个上下文
关于 z-index 的常见误解
我们通常需要在元素上设置position
属性为relative
或 absolute
,这样z-index
才能生效,但是也有一些例外,例如:
<style>
.box {
width: 50px;
height: 50px;
border: 3px solid;
background: silver;
}
.wrapper {
display: flex;
}
.second.box {
z-index: 1;
background: hotpink;
margin-top: 20px;
margin-left: -20px;
margin-right: -20px;
}
style>
<div class="wrapper">
<div class="first box">div>
<div class="second box">div>
<div class="third box">div>
div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
我们没有为.second.box
元素设置position
,但是设置了z-index
,这时同样生效。
一般来说,z-index
仅适用于“定位”元素(设置position
为static
以外的元素)。但 Flexbox
规范添加了一个例外:即使Flex
子项是静态定位的,它们也可以使用。
isolation
.wrapper {
isolation: isolate;
}
- 1
- 2
- 3
当我们将此声明应用于元素时,它只起到创建一个新堆栈上下文的作用。
,对于所有其他方法,堆栈上下文都是隐式创建的。而isolation
以最纯粹的方式创建一个堆叠上下文:
- 无需指定
z-index
值 - 可用于静态定位元素(
position: static;
) - 不会以任何方式影响子级的渲染
这是非常有用的,因为它可以让我们“封闭”一个元素的子元素。