z-index无效主因是父容器创建了层叠上下文,使子元素z-index仅在局部生效;需检查祖先节点是否触发层叠上下文(如opacity
直接设 z-index 却没效果,大概率不是写错了值,而是父容器触发了层
叠上下文(stacking context),把子元素“锁死”在局部层级里。此时子元素的 z-index 只在该上下文中起作用,无法越过父级去和外部元素竞争层级。
常见触发层叠上下文的属性包括:position 非 static + z-index 不为 auto、opacity 小于 1、transform 非 none、filter 非 none、will-change 指定相关属性等。
opacity: 0.99 或 transform: translateZ(0))验证是否恢复生效即使子元素设置了 z-index: 9999,如果它的直接父容器 z-index: 1,而旁边一个兄弟容器是 z-index: 100,那整个子树都会被压在下面——因为层叠比较发生在同一层叠上下文的同级元素之间。
解决的关键是:**控制层级的“入口点”必须在共同父级下对齐**。
transform 或 opacity,考虑将其上移到更高层级的容器,而非包裹目标元素的直接父级z-index;真正需要分层的,应让它们处于 DOM 同一层级(比如都挂载在 下)z-index 只对定位元素(position 为 relative、absolute、fixed 或 sticky)生效。静态定位(position: static,默认值)下设 z-index 完全无效,且不会触发层叠上下文。
常见误操作:
z-index: 10,忘了加 position: relative
* { position: static !important },覆盖了显式声明快速验证:在开发者工具中手动勾选元素的 position: relative,看是否立刻生效。
当多个带 transform 的容器层层嵌套(比如轮播图内部又套弹窗再套 tooltip),每一层都可能新建层叠上下文,最终导致最内层元素的 z-index 实际作用域极小。
典型结构问题:
…
这里 .tooltip 的 z-index 最高只能盖过 .slide 内部其他元素,但无法高于 .carousel 外的导航栏或遮罩层。
Portal 渲染到 下(React/Vue 均支持)position: fixed + z-index 统一管理overflow: auto)内嵌套 position: fixed 元素,它会相对于该容器定位而非视口层叠上下文不是 bug,是 CSS 规范的明确行为。真正难的不是加 z-index,而是看清当前元素处在哪一层“房间”里,以及这个“房间”的门朝哪开。