z-index 对 grid-item 不起作用,因其默认未建立层叠上下文;需添加 position: relative 等并设置 z-index 才生效,且受父容器是否创建新层叠上下文(如 transform)制约。

grid-item 的 z-index 为什么不起作用?
因为 z-index 只对「已建立层叠上下文」的元素生效,而默认情况下 grid item 不会自动创建层叠上下文——它只是网格容器里的一个普通子元素,渲染层级由 DOM 顺序和网格绘制规则决定。
常见错误现象:z-index: 999 写在某个 grid-item 上,但它依然被后面出现的 item 盖住;或者和父容器外的元素(比如固定定位弹窗)混排时层级错乱。
- 必须给该 item 显式触发层叠上下文:加
position: relative(或absolute/fixed)+z-index - 如果 item 内部有伪元素(如
::before),它们的层级受 item 自身层叠上下文限制,不能突破到外部容器层级 - 注意 grid 容器本身若设了
transform或opacity ,也会创建新的层叠上下文,把所有 item “框死”在里面,此时 item 的 <code>z-index只在该上下文中有效
grid-container 的 transform 怎么影响子项层级?
transform 是最隐蔽的层叠上下文触发器之一。只要 grid 容器设置了任意非 none 的 transform 值(哪怕只是 transform: translateZ(0)),它就立刻成为一个新的层叠上下文根节点。
使用场景:做动画、视差滚动、或绕过某些浏览器渲染 bug 时习惯加 transform: translateZ(0),但没意识到这会让整个 grid 的渲染层级“自成一派”。
立即学习“前端免费学习笔记(深入)”;
- 容器内所有 grid item 的
z-index比较只在该容器内部有效,无法和容器外其他元素(如position: fixed的导航栏)直接比大小 - 若需跨容器控制层级,要么去掉容器的
transform,要么把需要“浮出来”的元素移出 grid 结构(用 portal 或绝对定位模拟) - Chrome 和 Safari 对
will-change: transform的处理也类似,同样会隐式创建层叠上下文
多个 grid-item 重叠时,谁在上面?
当没显式设置 z-index 或层叠上下文时,grid item 的默认绘制顺序由两个因素共同决定:DOM 顺序 + 网格轨道位置。但后者仅在「同一网格区域」内起作用。
容易踩的坑:以为 grid-row: 1 / 3 的 item 一定盖在 grid-row: 2 / 4 的 item 上面——其实不是。CSS Grid 的绘制顺序优先看 HTML 中的兄弟顺序,再看是否落在同一网格单元格里。
- 如果两个 item 占据完全相同的网格区域(比如都设了
grid-area: 1 / 1 / 3 / 3),那么 DOM 中靠后的那个默认在上层 - 如果它们占据不同区域(比如一个在第1行,一个在第2行),即使视觉上重叠(因设置了
margin或transform移动),也不触发网格内的层叠比较,而是按常规块级流规则叠加 - 此时若想强制控制,必须让它们处于同一层叠上下文中,并用
z-index明确排序
grid + position: sticky 的层级陷阱
position: sticky 的元素在粘性生效时会脱离文档流并提升层级,但它是否能盖过同 grid 容器内的其他 item,取决于它有没有被包裹进一个新的层叠上下文。
典型问题:sticky 头部写在 grid item 里,滚动时被下方另一个 grid item 盖住,尤其在 Safari 中更明显。
- sticky 元素本身不会自动创建层叠上下文,所以它的层级仍受父 grid 容器约束
- 解决办法是给 sticky 元素加
position: sticky+z-index: 1,同时确保其父 grid item 没有z-index: 0或更低值(否则会把它压在下面) - 更稳妥的做法是让 sticky 区域脱离 grid 布局:用
position: sticky配合top: 0,并将其从 grid 容器中移出,改用display: contents或 wrapper 调整结构










