z-index在Grid中只对同级、已定位的子项生效;重叠需grid-area或grid-row/column实现,分层由DOM顺序+position+z-index共同决定,缺一不可。

直接说结论:z-index 在 Grid 区域内只对同级、已定位的子项生效;重叠本身靠 grid-area 或 grid-row/grid-column 实现,但“谁在上”由 DOM 顺序 + position + z-index 共同决定——缺一不可。
为什么写了 z-index 却没分层效果?
最常见原因是目标元素仍是 position: static(默认值),而 z-index 对 static 元素完全无效。这不是 Grid 的限制,是 CSS 层叠规则本身的要求。
- 检查 DevTools 的 Computed 面板,确认目标元素的
position值不是static - 正确写法是:
.item { position: relative; z-index: 2; }——relative不影响 Grid 布局位置,只激活层叠能力 - 别用
position: absolute单纯为了启用z-index,否则它会脱离 Grid 轨道,无视grid-column等设置 - 如果两个元素都用了
grid-area: "header",但一个被display: contents包裹过,它就不再是 Grid 子项,z-index不可比
grid-area 相同却没重叠?检查命名与分配
多个元素写相同 grid-area 值,不等于它们一定重叠——前提是父容器的 grid-template-areas 中该名称确实只占一个格子,且两个元素都是直接子元素。
- 拼写必须严格一致:
"sidebar"和"Sidebar"是不同区域;带引号和不带引号也不同(如sidebarvs"sidebar") - 用 DevTools Elements 面板直接看每个元素的
computed grid-area,比查源码更快定位是否真被分配到同一区域 - 临时加唯一后缀测试,比如把
grid-area: "overlay"改成"overlay-1"和"overlay-2",看是否还叠——不叠说明原命名没生效 - 确保父容器设置了
display: grid且定义了grid-template-areas,否则grid-area值会被忽略
父容器意外创建了层叠上下文,z-index 就失效
即使 position 和 z-index 都写了,层级仍错乱?大概率是父容器(Grid 容器本身)触发了新的 stacking context,把子项的 z-index 锁死在内部比较。
- 常见触发属性:
opacity: 0.99、transform: translateZ(0)、filter: blur(2px)、will-change: transform - 验证方法:在 DevTools 的 Computed 面板中搜这些属性,临时移除它们看
z-index是否恢复 - 替代方案:需要模糊背景时用
backdrop-filter: blur(4px)替代filter;需要半透明又不想触发上下文,改用background: rgba()而非opacity -
z-index比较只在同一个 Grid 容器内有效;跨容器重叠必须控制外层容器的z-index,而非子项堆数值
移动端 Safari 的兼容性坑:iOS 15.4 之前不支持子项 z-index
iOS 15.4 之前的 Safari 对 Grid 子项上的 z-index 支持不完整,尤其混用 transform 动画或 will-change 时,可能出现层级错乱或闪烁。这不是代码问题,是渲染引擎 bug,无法通过调整 CSS 规避。
- 降级策略:对关键重叠区域(如弹窗遮罩+按钮),避免依赖子项
z-index,改用position: fixed挂到body下,并统一用容器级z-index控制 - 不要给 Grid 子项同时加
transform和z-index,尤其在动画中——Safari 可能直接忽略后者 - 用
isolation: isolate强制创建层叠上下文虽可行,但会额外增加渲染开销,仅在必要时使用
真正难的不是写对语法,而是判断当前重叠是否真的发生在「同级 Grid 子项」之间——DOM 结构、display 类型、父容器层叠上下文,三者任一出偏差,z-index 就会静默失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











