z-index在同级元素间失效是因为它们分属不同层叠上下文;浏览器先按上下文分组,再在组内比较z-index。常见原因包括父容器创建了独立上下文、元素未定位、overflow裁剪或z-index:0意外触发上下文。

z-index 在同级元素间失效,是因为它们根本不在同一个层叠上下文中
两个元素即使 DOM 位置相邻、z-index 差 1000,只要分属不同层叠上下文(stacking context),就无法直接比较大小。浏览器不是比“谁的 z-index 数字大”,而是先按层叠上下文分组,再在组内比 z-index。常见陷阱是:你以为它们是“同级”,其实它们的父容器早已各自建立了独立上下文。
典型场景:.dropdown 在 #app 内,而遮挡它的 .header 是 body 直接子元素——它们的共同祖先虽是 body,但各自的父级已分别创建了上下文,导致 .dropdown 的 z-index: 999 压不住 .header 的 z-index: 10。
- 用 Chrome DevTools → Elements 面板右键目标元素 → “Show stacking context”,快速定位哪个祖先被标为
This element establishes a stacking context - 打开 Rendering 面板 → 勾选
Show layers panel,图层树里直接看到每个上下文节点,点一下高亮对应 DOM 元素 - 临时删掉疑似父级的
transform、opacity: 0.99、filter: blur(0)或will-change: transform,看遮挡是否立刻消失
检查目标元素是否真的参与了层叠计算
z-index 只对 position 为 relative、absolute、fixed 或 sticky 的元素生效。默认 position: static 下,哪怕写 z-index: 2147483647,DevTools 的 Computed 面板里 z-index 也显示为 auto 或 not applicable,说明它压根没进层叠流程。
- 在 DevTools 中选中该元素,搜
position,确认不是static - JS 动态插入或 Vue/React class 切换后,容易漏掉
position,或被其他样式规则覆盖重置 -
display: flex或grid的子项,不能靠父容器定位来“继承”层级能力,必须自己设position
父容器的 z-index: 0 比你想象中更危险
很多人以为加个 z-index: 0 很安全,其实它会强制创建新层叠上下文;而 z-index: auto(默认值)不会(前提是元素已定位)。一个 position: relative; z-index: 0 的父容器,等于主动给子元素建了个“结界”——子元素再高的 z-index 也出不去。
- 检查父容器是否意外设置了
position: relative+z-index: 0 - 若只是想让父容器参与层叠排序但不隔离上下文,保留
z-index: auto更稳妥 -
overflow: hidden、auto或scroll的父容器会裁剪子元素,z-index根本没机会起作用
别只盯着数字,先理清上下文边界和容器关系
真正决定谁在上的,是上下文容器本身的层级,而不是子元素的 z-index。比如 .header(z-index: 10)和它内部的 .dropdown(z-index: 999)永远不可能盖过 .content(z-index: 20),因为前两者被锁死在同一个上下文里,而这个上下文整体在 .content 下方。
- 修复思路不是把
.dropdown的z-index改成 9999,而是要么删掉.header触发上下文的属性,要么把.dropdown用position: fixed挂到body下(记得手动处理滚动偏移) - Bootstrap 等框架组件默认挂载位置不同(如
.toastappend 到body,.dropdown渲染在触发器同级),天然跨上下文,数值小也可能盖住数值大的 - 滥用
z-index: 9999会让后续模态框、通知栏等无法插入中间层级,甚至压住正在动画的过渡层
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











