grid子项z-index不生效的根本原因是未进入层叠上下文:必须设position: relative(不脱离布局),确保grid-column/row定义真实重叠区域,且父级未因opacity/transform/filter等创建独立堆叠上下文。

Grid 子项的 z-index 不生效,基本不是数值写小了,而是它压根没进层叠计算——要么 position 还是 static,要么被父容器悄悄关进了独立的 stacking context。
Grid 子项必须显式设 position: relative
Grid 布局本身不赋予子项层叠资格。即使你写了 grid-column: 2 / 3 和 z-index: 999,只要 position 没改,默认仍是 static,浏览器直接忽略 z-index,DevTools 里该属性会灰显、标为 (not applicable)。
- 加
position: relative是最安全的解法:它不脱离 Grid 轨道,grid-column和grid-row依然生效,只激活层叠能力 - 别用
position: absolute单纯为了启用z-index——它会让元素脱离 Grid 布局,grid-column等声明彻底失效 - Vue/React 中通过 class 切换显示时,要防其他样式规则把
position覆盖回static
重叠区域必须由 grid-column/grid-row 主动定义
z-index 只决定“谁在上”,不决定“是否重叠”。如果两个子项没真正占据同一网格区域,z-index 就没机会起作用。
- 危险写法:
grid-column: 2 / 2→ 区域宽度为 0,元素不可见;grid-column: 2虽等价于2 / 3,但易误判实际跨度 - 合法写法:
grid-column: 2 / 3(占第 2 列)、grid-column: 2 / -1(从第 2 列延伸到末尾) -
grid-row同理:起止线不能重合,且必须落在容器已定义的轨道范围内
父容器可能静默创建了 stacking context
哪怕 position 和 grid-column 都写对了,只要某个祖先元素满足以下任一条件,它就创建了独立的 stacking context,子项的 z-index 只能在里面比大小:
-
opacity小于 1(哪怕opacity: 0.999) -
transform不为none(包括transform: translateZ(0)、scale(1)) -
filter不为none(哪怕filter: blur(0)) -
will-change: transform或isolation: isolate
验证方法:在 Chrome DevTools Elements 面板逐级点击父节点,右侧面板 «Layout» 标签页看 «Stacking context» 是否突然变成 Yes;临时注释掉可疑属性,遮挡消失即坐实问题。
iOS Safari 15.4 之前有渲染 bug
旧版 Safari 对 Grid 子项上的 z-index 支持不完整,尤其混用 transform 动画或 will-change 时,可能出现层级错乱或闪烁。这不是代码问题,无法通过调整 CSS 规避。
- 降级策略:需要模糊背景时用
backdrop-filter: blur(4px)替代filter;需要半透明又不想触发上下文,改用background: rgba()而非opacity - 若必须支持旧 Safari,可考虑将关键浮层(如 tooltip、dropdown)用 JS 挂到
body下,再动态同步位置(慎用)
真正难的不是算清哪个值该写多少,而是每次调完 z-index,都要往上多看两层 DOM,确认那个刚被激活的 transform 或 opacity 没把你需要突出的元素关进盒子。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











