在CSS页面布局过程中,使用position属性对元素进行定位时,经常会出现多个定位元素互相重叠、部分内容被遮挡的情况,这时候需要通过position和z-index的配合来解决问题。

position属性对元素定位的基础影响
position属性决定了元素的定位方式,不同的取值会影响元素是否脱离文档流,以及是否可以作为z-index的生效载体。常见的position取值有以下几类:
- static:默认值,元素按照正常文档流排列,设置top、right、bottom、left属性无效,z-index也不会生效。
- relative:相对定位,元素相对于自身原位置进行偏移,不脱离文档流,z-index可以生效。
- absolute:绝对定位,元素脱离文档流,相对于最近的非static定位的祖先元素定位,z-index可以生效。
- fixed:固定定位,元素脱离文档流,相对于浏览器视口定位,z-index可以生效。
- sticky:粘性定位,元素在阈值范围内表现为relative,超过阈值后表现为fixed,z-index可以生效。
只有position取值为relative、absolute、fixed、sticky的元素,z-index属性才会生效,static定位的元素即使设置了z-index也不会产生层叠顺序变化。
z-index属性的作用规则
z-index属性用来设置定位元素的层叠顺序,取值可以是正整数、负整数、0,数值越大的元素会显示在更上层,遮挡数值更小的元素。需要注意z-index的生效前提是元素必须是定位元素(position不为static)。
来看一个简单的示例,两个绝对定位的div元素发生重叠,通过z-index调整显示顺序:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
.box1 {
position: absolute;
top: 50px;
left: 50px;
width: 200px;
height: 200px;
background-color: #ff0000;
z-index: 1;
}
.box2 {
position: absolute;
top: 80px;
left: 80px;
width: 200px;
height: 200px;
background-color: #00ff00;
z-index: 2;
}
</style>
</head>
<body>
<div class="box1">我是红色盒子,z-index为1</div>
<div class="box2">我是绿色盒子,z-index为2</div>
</body>
</html>
上述代码中,box2的z-index值更大,所以会显示在box1的上层,遮挡box1的部分内容。如果将box2的z-index改为0,那么box1会显示在更上层。
层叠上下文的影响
z-index的比较并不是全局的,而是在同一个层叠上下文中进行的。如果元素创建了层叠上下文,那么它的z-index只会在自身所在的层叠上下文内部比较,不会影响其他层叠上下文中的元素。
常见的创建层叠上下文的情况包括:
- 根元素(html标签)本身就会创建一个顶层叠上下文。
- position为absolute或relative,且z-index不为auto的元素。
- position为fixed或sticky的元素。
- flex容器的子元素,且z-index不为auto。
- opacity值小于1的元素。
- transform值不为none的元素。
来看一个层叠上下文导致z-index失效的示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
.parent1 {
position: relative;
z-index: 1;
width: 300px;
height: 300px;
background-color: #cccccc;
}
.child1 {
position: absolute;
top: 50px;
left: 50px;
width: 150px;
height: 150px;
background-color: #ff0000;
z-index: 100;
}
.parent2 {
position: relative;
z-index: 2;
width: 300px;
height: 300px;
background-color: #aaaaaa;
margin-top: -200px;
}
.child2 {
position: absolute;
top: 80px;
left: 80px;
width: 150px;
height: 150px;
background-color: #00ff00;
z-index: 1;
}
</style>
</head>
<body>
<div class="parent1">
父元素1 z-index为1
<div class="child1">子元素1 z-index为100</div>
</div>
<div class="parent2">
父元素2 z-index为2
<div class="child2">子元素2 z-index为1</div>
</div>
</body>
</html>
这个示例中,parent1的z-index是1,parent2的z-index是2,所以parent2整体显示在parent1的上层。child1的z-index虽然是100,但它只在parent1的层叠上下文内部比较,无法超过parent2的层叠顺序,所以child1还是会被parent2遮挡,即使它的z-index数值更大。
解决元素重叠遮挡的常用方法
1. 调整z-index数值
如果是同层叠上下文内的定位元素重叠,直接调整z-index的数值即可,将需要显示在上层的元素z-index设置得更大。
2. 检查position属性
如果z-index设置后没有生效,首先检查元素的position是否为static,如果是的话需要修改position为relative、absolute等可定位的属性。
3. 避免不必要的层叠上下文
如果不是必须,不要随意给元素设置会创建层叠上下文的属性,比如不必要的opacity、transform等,避免z-index的比较范围被限制。
4. 调整元素DOM顺序
在同一个层叠上下文中,如果z-index相同,那么后渲染的DOM元素会显示在上层。这时候可以调整元素的DOM顺序,把需要显示在上层的元素放在后面。
5. 使用开发者工具排查
如果重叠问题比较复杂,可以打开浏览器的开发者工具,查看元素的层叠上下文情况,找到具体是哪个父元素创建了层叠上下文,再针对性调整z-index或者层叠上下文结构。
注意事项
不要随意给元素设置非常大的z-index数值,比如9999、10000等,这样后续如果需要调整层叠顺序会很麻烦,建议按照层级规划设置合理的z-index数值,比如弹窗层用1000,下拉菜单用500,普通定位元素用10等。
另外,z-index为负数时,元素会显示在正常文档流元素的下层,如果有需要让定位元素显示在背景层的场景,可以使用负的z-index,但要注意元素是否创建了层叠上下文,避免无法显示的问题。