z-index不生效主因是元素未处于同一层叠上下文。常见原因:目标元素position为static;父元素含opacity、transform等触发隐式层叠上下文;两元素分属不同层叠上下文。可通过DevTools的Computed面板查看stacking context确认。

z-index 不生效,99% 是因为元素没进同一个层叠上下文,而不是数值不够大。
为什么写了 z-index 却还是被盖住
常见现象:给弹窗加了 z-index: 9999,结果仍被导航栏压着;或者两个 position: absolute 元素堆在一起,调了 z-index 没反应。
- 目标元素的
position值仍是static(默认值)→z-index完全被忽略 - 它的某个父元素有
opacity: 0.99、transform: translateZ(0)、filter: blur(1px)或will-change: transform→ 隐式创建新层叠上下文,子元素的z-index被“关在里面” - 两个要比较的元素分别属于不同父容器,而这两个父容器各自创建了独立层叠上下文 → 它们根本不在同一个“比大小”的场子里
怎么快速确认是否在同一个层叠上下文里
打开 Chrome DevTools,选中目标元素,在 «Computed» 面板搜索 stacking context:
- 若显示
Yes,说明它自己或某个祖先已创建新上下文 - 逐级向上点父节点,看哪个节点的
position+z-index(非auto)或opacity - 临时删掉可疑父元素的
transform或opacity,观察遮挡是否立刻消失——这是最直接的验证方式
怎样让 z-index 真正起作用
不是堆数字,而是理清定位链和上下文边界:
立即学习“前端免费学习笔记(深入)”;
- 确保目标元素有
position: relative、absolute、fixed或sticky—— 缺一不可 - 若想让子元素能跨父容器竞争层级,就把它们的共同祖先设为定位元素,并统一提升它的
z-index,而不是只调子元素 - 移动端 Safari 对
transform+z-index组合特别敏感:只要父容器用了transform,又没显式设z-index,子元素的z-index就可能失效;稳妥做法是同时加position: relative和z-index: 0 - 用 CSS 自定义属性管理层级,比如
:root { --z-modal: 1000; },再写.modal { z-index: var(--z-modal); },避免魔数和冲突
两个 position: absolute 元素怎么正确排序
同级、同层叠上下文时,规则很明确:
- 都设了
z-index:数值大的在上 - 一个设了(如
z-index: 10),另一个是auto:设了的在上 - 都没设(都是
auto):按 DOM 顺序,后出现的在上 - 必须显式写
top/left,否则默认都落在top: 0; left: 0,视觉重叠不是层级问题,是定位缺失
真正容易被忽略的是:父容器没设 position: relative,导致 absolute 元素直接相对于 viewport 定位,参考系错位会让所有 z-index 失去意义。


















