z-index失效的根本原因是元素未参与层叠计算,而非数值过小;常见于未定位或被祖先元素创建的独立层叠上下文隔离;需通过devtools检查position和z-index适用性,并排查opacity、transform等隐式触发层叠上下文的属性。

z-index 在不同堆叠上下文里失效,不是数值不够大,而是你试图让两个“不在同一个世界”的元素直接比高低——浏览器根本不允许跨上下文比较。
为什么 z-index 写了却像没写一样
最常见现象:一个 z-index: 9999 的 tooltip 总被 z-index: 10 的 header 盖住。原因不是 tooltip 数值小,而是它的父容器(比如带 opacity: 0.99 或 transform: translateZ(0) 的卡片)已创建新堆叠上下文,tooltip 的 z-index 只在该卡片内部生效。
- 用 Chrome DevTools 选中 tooltip → «Computed» 面板查
z-index,若显示为(not applicable)或灰显,说明它根本没参与层叠计算 - 再点父节点 → «Layout» 标签页看 «Stacking context» 是否为
Yes;第一个标为Yes的就是“结界源头” - 临时注释掉父级的
transform、opacity或filter,遮挡立刻消失——这就是实锤
哪些属性会静默创建堆叠上下文
这些样式看着无害,但只要偏离默认值,就强制生成独立层级空间:
-
opacity小于 1(哪怕opacity: 0.999) -
transform不为none(包括transform: scale(1)、translateZ(0)、rotate(0.0001deg)) -
filter不为none(哪怕filter: blur(0)) -
will-change: transform或will-change: opacity isolation: isolate-
position: fixed或sticky且z-index不是auto -
z-index: 0(注意:它会创建新上下文,而z-index: auto不会)
修复的关键不是堆数字,而是提级或绕开
子元素再怎么调 z-index,也破不了父级的“结界”。必须从结构层面解决:
- 如果父容器的
transform或opacity非必需(比如只为触发硬件加速),直接删掉——最干净 - 如果必须保留(如淡入动画),就把需要浮出的元素(如 dropdown、modal)用 JS 移到
document.body下,配合position: fixed手动定位(别忘了监听scroll和resize更新位置) - 更可控的做法:给那个触发上下文的父容器自身设高
z-index(比如z-index: 105),让它整体抬高,而不是在内部疯狂堆z-index: 9999 - Tailwind 用户注意:
zIndex必须在tailwind.config.js中以对象语法定义(如{ 'modal': '60' }),改完要重启 dev server;z-[999]动态拼接在构建时不会被扫描
移动端和 iframe 的特殊限制
iOS Safari 对 body 和 html 极其敏感:
-
html { transform: translateZ(0) }→ 整个页面变成单一层叠上下文,“最高”的弹窗也只能在它内部排第一 -
body { overflow: hidden }→ 可能导致position: fixed元素滚动时被裁切 -
iframe、video、旧版select使用原生渲染层,天然高于 DOM;z-index对它们无效,只能靠调整 iframe 的allow属性或换用position: absolute+z-index容器包裹
真正难的不是写多大的 z-index,而是看清哪一层“结界”把你卡住了——DevTools 的 «Layers» 面板和 «Stacking context» 标记,才是你该盯住的地方。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











