z-index并非设了就生效,必须在层叠上下文中才有效:它仅作用于已定位元素(position非static),且数值只在所属上下文内可比;父元素创建新上下文后,子元素z-index再大也无法突破该上下文边界。

z-index 不是“设了就起作用”的属性,它必须在特定的层叠上下文中才能正确比较和生效。脱离层叠上下文谈 z-index,就像在不同楼层比谁站得更高——根本不在同一维度。
z-index 生效的前提:元素必须参与层叠上下文
一个元素要能用 z-index 控制层级,首先要“进入”某个层叠上下文。这个上下文不是全局统一的,而是可以嵌套、可以隔离的。关键点在于:
- z-index 只对已定位元素有效:position 必须是 relative、absolute、fixed 或 sticky(不能是 static)
- z-index 的数值只在它所属的层叠上下文内部有意义,无法跨上下文直接比较
- 父元素一旦创建了新层叠上下文,它的子元素就只能在这个“小世界”里排高低,再大的 z-index 也出不去
哪些情况会悄悄创建新的层叠上下文?
除了显式设置 position + z-index,很多看似无关的 CSS 属性也会触发层叠上下文,这是最常踩坑的地方:
- opacity 小于 1(比如 opacity: 0.99)
- transform 有值(哪怕只是 transform: translateZ(0) 或 rotate(0deg))
- filter 不为 none(如 filter: blur(0px)、drop-shadow(0 0 0 #000))
- will-change 指向上述任一属性(如 will-change: transform)
- perspective、clip-path、mask 等现代布局属性
这些属性本身不带 z-index,但会让元素变成“层叠上下文根”,其内部所有子元素的堆叠顺序,从此只由该容器内部的 z-index 决定。
立即学习“前端免费学习笔记(深入)”;
父子元素之间的真实关系
很多人以为给父元素设 z-index=10,再给子元素设 z-index=100,子元素就能盖住其他兄弟容器——其实不行。
- 如果父元素设置了 z-index(且非 auto),它就创建了一个新层叠上下文
- 子元素的 z-index=100,只是在父容器这个“小房间”里排第一,整个“房间”仍按父元素的 z-index=10 参与外部排序
- 真正决定覆盖关系的是父容器的层叠等级,而不是子元素的 z-index 数值
想让子元素跳出父级限制?要么移除父元素的层叠上下文(比如去掉 z-index 或 opacity),要么把该子元素提升到更高层级的上下文里(例如用 fixed 定位脱离父级流)。
调试 z-index 问题的实用思路
当发现 z-index 不生效或效果反直觉时,不要只盯着数值大小,优先检查:
- 目标元素是否设置了 position(且不是 static)?
- 它的任意祖先是否无意中创建了层叠上下文(比如用了 opacity 或 transform)?
- 两个要比较的元素是否处在同一个层叠上下文内?如果不是,它们的 z-index 互不干扰
- 浏览器开发者工具中,该元素的 z-index 是否显示为灰色?灰色 = 未生效,说明定位条件不满足
真正理解层叠上下文,不是记住一堆规则,而是建立起“每个上下文都是独立 Z 轴空间”的直觉。z-index 是坐标,层叠上下文是坐标系——没有坐标系,坐标就没有意义。



















