z-index失效的根本原因是元素未定位或被祖先的独立层叠上下文隔离;需确保position非static,且检查祖先是否因opacity、transform等属性创建了新层叠上下文。

z-index 失效,不是数值太小,而是元素根本没进入浏览器的层叠计算流程——要么没定位,要么被锁在某个祖先创建的独立层叠上下文中。
元素没设置 position 就写 z-index
z-index 只对已定位元素生效,position: static(默认值)完全忽略它。哪怕 DOM 结构再合理、z-index 写成 999999,也毫无作用。
- 用 Chrome DevTools 的 «Computed» 面板检查目标元素,确认
position不是static - 最小验证法:临时加
position: relative(不改变布局),再看z-index是否立刻起效 - Vue/React 中动态切换 class 时,容易只加了
z-50类,却漏掉relative或absolute定位类
父级或祖先元素静默创建了层叠上下文
只要某个祖先元素设置了以下任一属性(且值偏离默认),就会强制生成新层叠上下文,把整个子树“关进盒子”:opacity()、<code>transform(!= none)、filter(!= none)、will-change、isolation: isolate、position: fixed/sticky 且 z-index 不是 auto。
- 在 DevTools 的 Elements 面板中逐级点击父节点,右侧面板 «Layout» 标签下看 «Stacking context» 是否为 Yes
- 常见实锤场景:
opacity: 0.99的卡片、transform: translateZ(0)的轮播容器、backdrop-filter: blur(1px)的弹窗外层 - 临时注释掉这些属性,遮挡消失 → 就是它;若必须保留(如动画),就给该父容器自身设高
z-index(如z-index: 105),而不是堆子元素的z-index
响应式断点里激活的 transform / opacity 意外触发上下文
媒体查询中看似无害的一行 transform: scale(1) 或 opacity: 0.99,会在特定断点下突然让父容器变成层叠上下文根节点,导致原本正常的 z-index 突然失效。
立即学习“前端免费学习笔记(深入)”;
- 切到对应断点,在 DevTools «Computed» 面板搜索
transform,确认是否从none变成了具体值 - Flex/Grid 容器在断点中启用时,若同时带
opacity或transform,子项的z-index会被整体隔离 - 移动端尤其注意:iOS Safari 对
translateZ(0)更敏感,可能比桌面端更早“结界化” - 所有涉及
position变更的媒体查询(如从static切到fixed),必须同步补上z-index,否则元素虽浮起,却落在默认层(常被 header 盖住)
z-index: 0 和 z-index: auto 的语义差异被忽略
z-index: 0 不是“没效果”,而是会显式创建新层叠上下文;而 z-index: auto(配合已定位元素)不会创建上下文,仅参与当前上下文内的排序。
- 错误写法:
.modal { position: absolute; z-index: 0; }→ 整个 modal 被锁进新上下文,内部按钮再怎么写z-index: 999也无法盖过外部 header - 正确做法:需要全局层级控制时,优先用
z-index: auto(前提是已定位),或直接提升 modal 容器自身的z-index(如z-index: 1050) - 负值陷阱:
z-index: -1会让元素沉到其父上下文的背景和边框之下,在响应式切换中极易“突然消失”
真正难的不是记住哪些属性会触发层叠上下文,而是在每次改完样式后,顺手往上多点两层 DOM,看看那个刚被激活的 transform 或 opacity,有没有悄悄把你需要突出的元素关进了盒子。


















