z-index无效主因是元素未定位或被层叠上下文限制;需确保position非static,并排查祖先节点是否意外创建stacking context(如opacity<1、transform非none等)。

z-index写了却没用,先确认元素有没有定位
浏览器压根不读z-index,只要元素的position是static(默认值)。这不是“效果弱”,是“不参与层叠计算”。
常见漏点:
• JS 动态插入浮层时只设z-index,漏掉position: fixed或position: absolute
• Vue/React 中 class 切换后,响应式样式把position覆盖回static
• display: flex容器里的子项,误以为能直接靠z-index控制层级——它确实可以,但前提是自己已设position非static
被父级“关进盒子”了:检查 stacking context 的真实来源
移动端 z-index 失效,99% 是因为某个祖先节点静默创建了层叠上下文(stacking context),把子元素锁死在里面比大小。
这些属性看着无害,但只要偏离默认值就触发:
• opacity 小于 1(哪怕 opacity: 0.999)
• transform 不为 none(包括 transform: translateZ(0)、scale(1)、rotate(0.0001deg))
• filter 不为 none(哪怕 filter: blur(0) 或 filter: opacity(1))
• will-change: transform 或 will-change: opacity
• isolation: isolate
在 Chrome DevTools 的 Elements 面板中逐级点击父节点,右侧面板 Layout 标签页下看「Stacking context」是否突然变成 Yes;重点盯那些“没写 z-index 却显示 Yes”的节点。
iOS Safari 中 fixed 元素被降级,要特别防 body/html 上的 transform
移动端 Safari 对 body 和 html 的渲染限制极严:
• body { overflow: hidden } → 导致 position: fixed 元素滚动时被裁切
• html { transform: translateZ(0) } → 整个文档变成一个层叠上下文,“全局最高”的弹窗也只在它内部排第一
• 只要父容器有 transform、opacity < 1 或 filter,iOS Safari 就可能忽略 position: fixed 的语义,让它退化为 absolute
快速验证:打开 Safari Web Inspector 或 Chrome Remote Debugging,逐级点击 html → body → 根容器,看 «Computed» 里是否有 stacking context: yes;修复优先级:先删 body 和 html 上所有 transform、opacity、filter,再确保 min-height: 100vh 存在。
临时验证和长期解法:别堆数字,要提级或绕开
真正难的不是写多大的 z-index,而是看清哪一层“结界”把你卡住了。
临时验证最快方式:
• 注释掉疑似父级的 transform 或 opacity,观察遮挡是否立刻消失
• 在 DevTools 中手动给该父级加 z-index: 0 + position: relative,看是否恢复预期层级
长期可用方案:
• 把需要浮出的元素(如 modal、tooltip)用 createPortal(React)或 Teleport(Vue)挂到 document.body 下,彻底脱离干扰上下文
• 如果父容器必须保留 transform(比如做动画),就别在它里面调子元素 z-index,改为给该父容器自身设高 z-index,让它整体“抬高”
• 避免用 translateZ(0) 当“硬件加速开关”,现代浏览器多数场景已无需硬加速;改用 will-change: opacity(更轻量)或直接删掉
立即学习“前端免费学习笔记(深入)”;


















