之前使用 z-index
停留在数值越大层级越高的认知,直到最近遇到一个问题。明明z-index
最大了还是会被其他元素遮挡,这是为何呢?
层叠上下文
通常情况下,网页的布局都在二维平面里,但这种布局无法满足复杂的场景。css2.1中提出三维模型,除了x,y轴之外,增加了z轴,一个从屏幕垂直向外的坐标轴,所有的盒子都在三维模型中。
层叠上下文就是对这些 HTML 元素的一个三维构想。众 HTML 元素基于其元素属性按照优先级顺序占据这个空间。
如何声明一个层叠上下文
方法有很多,我只列举几个常用的,其他请参考MDN
- 文档根元素(html)
- postion显示指定为非
static
,且z-index
不为auto
层叠上下文特性
- 层叠上下文的子元素可以继续声明层叠上下文
z-index
属性只有在同一层叠上下文中比较才有意义- 对于非层叠上下文的元素,被父层叠上下文同化
z-index
同一层叠上下文中
- 定位元素层数始终高于普通元素
- 同是定位元素
z-index
越大,则层数越高,越在上层展示 z-index
默认值是0z-index
相同的情况下,按照元素出现顺序层叠
看下例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div.box1{
width: 500px;
height: 200px;
border: 1px solid rebeccapurple;
position: relative;
}
div.box11{
width: 50px;
height: 50px;
background-color: greenyellow;
position:relative;
}
div.box111{
width: 50px;
height: 50px;
background-color:skyblue;
position: absolute;
left: 200px;
z-index: 10;
}
div.box112{
width: 50px;
height: 50px;
background-color:gray;
position: absolute;
left: 210px;
z-index: 1;
}
div.box12{
margin-top: -10px;
width: 50px;
height: 50px;
background-color:orange;
}
</style>
</head>
<body>
<div class="box1">
<div class="box11">11
<div class="box111">111</div>
<div class="box112">112</div>
</div>
<div class="box12">
12
</div>
</div>
</body>
</html>
box11
开启了定位所以层级要比box12
高,即使box12
在文档中的出现顺序比box11
晚。
box111
和box112
是同一层叠上下文的兄弟元素,z-index
越高越先展示。
同一层叠上下文比较简单,也是常见的情况。
不同层叠上下文
不同层叠上下文则不可以简单通过 z-index
来比较优先级,需要先找到共同的祖先层叠上下文,然后在同一祖先下找各自的第二祖先层叠上下文,直到找到自身,再比较第二祖先的优先级。
先看下错误示范
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div.box1{
width: 500px;
height: 200px;
border: 1px solid rebeccapurple;
position: absolute;
}
div.box11{
width: 50px;
height: 50px;
background-color: greenyellow;
position:absolute;
z-index: 10;
}
div.box111{
width: 50px;
height: 50px;
background-color:skyblue;
position: absolute;
left: 100px;
z-index: 1;
}
div.box12{
width: 50px;
height: 50px;
background-color:orange;
position: absolute;
top: 40px;
z-index: 1;
}
div.box121{
width: 50px;
height: 50px;
background-color:rebeccapurple;
position: absolute;
left: 100px;
z-index:10;
}
</style>
</head>
<body>
<div class="box1">
<div class="box11">11
<div class="box111">111</div>
</div>
<div class="box12">12
<div class="box121">121</div>
</div>
</div>
</body>
</html>
虽然 box121
的z-index
要比box-111
的值大,还是被box111
覆盖了。
我们按照上面的思路来捋一下,box111
和box121
的共同祖先上下文是box1
,box1
下分别有box11
是box111
的祖先,box12
是box121
的祖先,box111
的z-index
大于box-121
的z-index
,所以无论怎么增加box112
的z-index
都会被box111
覆盖。
也就是说在同一层叠上下文中才认z-index
,你的祖先被盖了冒了,那下面的所有子元素都低人一等。
再来看一个例子
我们只是把上面的 box12
的z-index
改成 auto
,看下效果
box121
给祖先挣了口气,盖住了box111
。因为auto
会让开启定位的元素丢失层叠上下文,box111
的第二祖先是box11
而box121
的第二祖先变成了自身。box121
的z-index
等于box11
的z-index
,但是位置靠后,所以优先展示。
其实是box121
盖住了box11
,不是一辈儿的,不跟你玩了。
实际上,并不是所有元素都会开启层叠式上下文,只不过定位元素设置z-index:auto
便不会开启上下文。box12
是普通元素,也会是上面的情况。
那假如box121
也不开启层叠上下文呢,那就相当于开启定位元素和普通元素的比较,自然是开启定位的元素层级更高了。
总之,不同层叠上下文比较同辈分的祖先的优先级即可。