z-index仅对定位元素(position为relative、absolute、fixed或sticky)生效,非定位元素设置无效;层叠顺序受层叠上下文约束,每个上下文内独立排序,父级的transform、opacity等属性会隐式创建新上下文,导致子元素z-index无法突破该层级。

z-index 只对定位元素生效,非定位元素设了也无效
很多人给 div 直接加 z-index: 999 却发现没反应,根本原因是它没触发定位上下文。CSS 中只有 position 值为 relative、absolute、fixed 或 sticky 的元素,z-index 才起作用。默认的 static 会忽略 z-index 设置。
实操建议:
- 先确认目标元素有
position: relative(最常用,不改变布局流)或对应定位方式 - 避免对纯文本、
span等内联元素直接设z-index,需先加position: relative和display: inline-block(如需占位) - 父容器若用了
transform、filter、will-change等属性,也可能隐式创建层叠上下文,导致子元素z-index相对父级生效而非全局——这点常被忽略
层叠顺序不是只看 z-index 数值,还要看层叠上下文
z-index 不是全局“绝对排名”,而是分层管理的。每个层叠上下文(stacking context)内部独立排序,外层的低 z-index 元素,可能盖过内层的高 z-index 元素。
哪些情况会创建新的层叠上下文?
立即学习“前端免费学习笔记(深入)”;
- 根元素(
html)天然是一个 - 设置了
z-index且position不为static的元素 - 设置了
opacity小于 1、transform、filter、will-change等属性的元素
比如:父容器 div#modal 设了 transform: scale(1),它就创建了新层叠上下文;其子元素即使 z-index: 9999,也无法越过该容器,去盖在同级的另一个 z-index: 10 的弹窗上。
定位元素的默认层叠顺序:谁后写谁在上,但受层叠上下文约束
在同一个层叠上下文中,未设置 z-index 的定位元素,遵循 HTML 源码顺序:后面出现的元素自然盖在前面的上面(类似图层叠放)。这个行为稳定,可作为轻量级控制手段。
但要注意边界情况:
- 两个同级
position: relative元素,都没设z-index→ 后写的那个在上 - 一个设了
z-index: 1,另一个没设 → 设了的一定在上(哪怕它写在前面) - 如果其中一个父容器已创建层叠上下文,则它的整个子树都“被锁进”该层级,不再和外部兄弟比顺序
示例:
<div class="box a">A</div> <div class="box b">B</div>若两者都
position: relative 且无 z-index,则 B 盖 A;但若 A 的父容器有 opacity: 0.99,那 A 整个子树就被压到 B 下面,无论怎么调 A 内部的 z-index 都没用。
移动端和 Safari 中 z-index 的常见坑
iOS Safari 对层叠上下文更敏感,尤其涉及 transform 和 fixed 定位时。常见表现是:弹窗遮不住 input 或视频控件,或者下拉菜单突然被截断。
排查与修复建议:
- 检查是否有父级无意中加了
transform: translateZ(0)或will-change: transform—— 这类“优化”常引发意外层叠上下文 - 使用
fixed定位的弹窗,若被body上的transform影响,可尝试给body加transform: none !important(慎用,可能影响其他动效) - 安卓 WebView 或旧版 Chrome 中,
z-index为负数(如-1)可能导致元素不可点击,尽量用正整数
真正难调的不是数值大小,而是你不知道哪个祖先悄悄建了个层叠上下文——打开浏览器开发者工具的“Layers”面板(Chrome)或“3D View”(Safari),能直观看到层叠结构。










