z-index失效主因是祖先元素创建层叠上下文,使子元素z-index仅在内部生效;需检查opacity

z-index 失效,几乎从不因为数值写小了,而是你没意识到某个祖先元素已经用 opacity、transform 或 filter 悄悄建了个“层叠盒子”,把目标元素关在里面比大小了。
为什么加了 z-index 还是被盖住?先看 position 有没有生效
最基础但最高频的错误:写了 z-index: 999,却忘了元素的 position 是 static(默认值)。此时浏览器直接忽略 z-index,连 warning 都不报。
- 用 Chrome DevTools 的 «Computed» 面板检查目标元素,搜
position,确认不是static - 临时加一行
position: relative(不影响文档流),立刻验证是否恢复层级控制 - JS 动态插入时容易漏掉
position声明;Vue/React 中 class 切换后,也要确保定位属性没被其他规则覆盖 -
display: flex或grid容器的子项,即使没设position,也能响应z-index,但仅限该容器内 —— 仍受父级层叠上下文限制
父元素触发了层叠上下文,子元素的 z-index 就“作废”了
只要某个祖先元素满足以下任一条件,它就创建了新的层叠上下文(stacking context),它的所有子元素的 z-index 只在它内部比大小,无法和外部同级元素竞争:
-
opacity小于 1(哪怕opacity: 0.999) -
transform不为none(包括看似无害的transform: translateZ(0)、scale(1)) -
filter不为none(哪怕filter: blur(0)) -
will-change: transform或will-change: opacity isolation: isolate-
position: fixed或sticky且z-index非auto
实操建议:
- 在 Chrome DevTools 的 Elements 面板中逐级点击父节点,右侧面板 «Layout» 标签页里留意 «Stacking context» 是否突然变成
Yes - 临时注释掉父级的
transform或opacity,看遮挡是否立刻消失 —— 这是最快定位手段 - 别只修子元素;要么删掉父级触发上下文的属性,要么把需要“突围”的元素(如
dropdown、tooltip)用position: fixed挂到body下(记得手动处理滚动偏移)
z-index: 0 和 z-index: auto 看似一样,实际效果截然不同
很多人以为加个 z-index: 0 很安全,其实它会强制创建新层叠上下文 —— 而 z-index: auto(默认)不会(前提是元素已定位)。这个细节常导致“明明啥都没动,突然就盖不住了”。
- 检查父容器是否意外设置了
z-index: 0+position: relative,这等于主动建了个结界 - 如果只是想让元素参与层叠排序但不想隔离上下文,用
z-index: auto更稳妥 -
z-index: -1会让元素沉到父上下文的背景和边框之下,慎用
真正难的不是堆数字,而是看清谁在哪个盒子里比大小
一旦有 transform、opacity 或 filter 出现在 DOM 路径上,就得停下来问一句:这个“盒子”,是不是我真想让它当根?z-index 的值再大,也跨不出它爹的边界。移动端还要额外注意 translateZ(0) 在某些 WebView 中会强制降级为 fixed 渲染行为,进一步扰乱预期层级。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











