z-index仅对position为relative、absolute、fixed或sticky的定位元素生效;static元素设置z-index无效;父容器创建层叠上下文会限制子元素z-index的作用范围,使其仅在该上下文中比较。

z-index 只对定位元素生效
很多人给元素设了 z-index 却没效果,根本原因是该元素的 position 值是 static(默认值)。z-index 不会作用于非定位元素。
-
position: relative、absolute、fixed、sticky才能触发层叠上下文(stacking context),让z-index生效 -
position: static元素哪怕z-index: 9999也完全被忽略 - 注意:
position: relative不改变文档流位置,但已满足z-index的前提条件
父容器创建层叠上下文会截断子元素的 z-index 比较范围
子元素的 z-index 只在**同一层叠上下文内**起作用。一旦父元素自身形成了新的层叠上下文(比如设置了 opacity: 0.99、transform: translateZ(0)、will-change: transform 或带 z-index 的定位值),它的所有子元素就只能在这个“小世界”里比高低,无法和外部兄弟元素直接比。
- 常见陷阱:
header设了z-index: 100,里面一个dropdown设了z-index: 9999,但依然被页面右侧一个z-index: 200的侧边栏盖住——因为header的z-index(或隐式层叠上下文)整体低于侧边栏 - 验证方法:浏览器开发者工具中查看元素的 “Computed” 面板,找
stacking context提示 - 临时调试技巧:给疑似“卡住”的父容器加
outline: 1px solid red,确认它是否意外创建了上下文
z-index 数值没有绝对意义,只在同级比较时有效
z-index 不是全局“海拔高度”,而是相对当前层叠上下文的排序编号。两个不同父容器下的元素,即使数值差很大(如 1 vs 9999),也可能因父级上下文层级低而整体被压在下面。
- 不要迷信大数字:写
z-index: 999999解决不了跨上下文遮挡问题 - 推荐做法:按功能分层定义常量,例如:
/* CSS custom properties for stacking */ :root { --z-nav: 10; --z-dropdown: 20; --z-modal: 100; --z-toast: 200; } - 避免用
z-index: auto(默认值)混在显式设置中——它会让元素进入“默认层叠顺序”,行为难以预测
fixed / sticky 定位元素天然脱离文档流,z-index 行为更敏感
position: fixed 和 position: sticky 元素默认相对于视口建立层叠上下文,它们的 z-index 会直接参与根层叠上下文的排序,因此更容易和其它 fixed 或根级 absolute 元素冲突。
立即学习“前端免费学习笔记(深入)”;
- 典型问题:导航栏
position: fixed+z-index: 10,弹窗position: fixed+z-index: 50,但弹窗里的select下拉仍被导航栏盖住——因为原生select在某些浏览器(尤其是旧版 Safari/IE)中渲染在独立图层,无视普通z-index - 解决方案:对弹窗整体加
transform: translateZ(0)强制创建新层叠上下文,或改用自定义下拉组件 -
sticky元素在粘住状态时行为等同于fixed,未粘住时则按正常文档流排序,这点容易被忽略
层叠逻辑不是线性堆叠,而是树状嵌套。真正难的不是记住 z-index 数字,而是看清当前元素处在哪一层上下文中、它的父级有没有悄悄把它“关进小房间”。










