z-index失效主因是父元素创建堆叠上下文或子元素未定位;需先确认position非static,再逐级检查opacity<1、transform非none等触发属性,并通过DevTools验证Stacking context。

z-index 层级失效,几乎从不因为 CSS 引入顺序本身,而是引入的样式里悄悄触发了堆叠上下文(stacking context)——顺序只是暴露了问题,不是根源。
为什么改引入顺序没用,反而更乱?
很多人发现把 modal.css 放在 base.css 后面,弹窗还是被盖住,于是反复调换顺序。这无效,因为:
- CSS 文件加载顺序只影响规则覆盖优先级(比如同名属性谁赢),但
z-index是否生效,取决于 DOM 节点是否处于同一层叠上下文,跟文件先后无关 - 真正起作用的是:某个被引入的样式(比如
card.css里的opacity: 0.95)在父容器上静默创建了新堆叠上下文,子元素的z-index立刻被“关进去” - 你调顺序,只是让不同上下文的“盒子”被创建得更早或更晚,但盒子本身还在
检查 z-index 是否被 “not applicable” 标灰
打开 Chrome DevTools,选中目标元素,在右侧面板「Computed」里搜 z-index:
- 如果显示为
(not applicable)或文字灰显 → 元素没定位,position是static,直接忽略z-index - 如果显示为具体数值(如
999),但依然被盖 → 说明它已进入某个父级堆叠上下文,数值只在内部有效 - 临时加一行
position: relative,再看z-index是否变黑、变可读 —— 这是最快验证定位缺失的手段
定位那个“结界制造者”父元素
在 Elements 面板里,从目标元素开始逐级点开父节点,每点一个,看右侧面板 Layout 标签页里的「Stacking context」字段:
立即学习“前端免费学习笔记(深入)”;
- 只要它突然变成
Yes,就找到了“结界源头” - 重点盯那些没写
z-index却标为Yes的节点 —— 它大概率用了:opacity: 0.99、transform: scale(1)、filter: blur(0)、will-change: transform - 临时注释掉该父元素的这些属性,遮挡立刻消失 → 验证成功
- 修复不是删动画,而是给这个父容器加
position: relative+ 合理z-index(比如z-index: 100),让它成为可控的层级锚点
避免 z-index: 0 成为隐形陷阱
很多 UI 组件库默认给容器设 z-index: 0,以为“安全”,实际是埋雷:
-
z-index: 0在position非static时,会强制创建新堆叠上下文 - 而
z-index: auto不会(前提是已定位) - 检查你引入的第三方 CSS(比如 Ant Design、Bootstrap)里是否有类似规则:
.ant-card { position: relative; z-index: 0; } - 如有,要么覆盖成
z-index: auto,要么干脆移除z-index声明,只留position
真正要动的往往不是那个写了 z-index: 9999 的按钮,而是它上面第三层、看起来毫无威胁的 opacity: 0.99 卡片容器 —— 它不声不响,就把整个子树锁死了。


















