先记住这个答案
普通嵌套 Grid 会独立计算自己的列,父子元素容易对不齐。子网格在列轴写 grid-template-columns: subgrid 后,沿用父网格中自己跨过的列轨;父级这段轨道上的命名线也可供子项目使用。它可以再给这些线加局部名字,但不会自动继承父网格中没有覆盖到的其他列。
subgrid按轴继承父轨道- 父级对应线名会传到子网格
- 子网格可再添加自己的线名
- 可用范围由父项目跨度决定
从父级跨列范围开始看
假设父网格有四列,卡片作为父网格项目只跨第 2、3 列。卡片内部设为列子网格后,它拿到的就是两列和相应边界线,不是四列完整模板。卡片内部的数字线号从自己的起点重新计数;若想避免父子层级切换时数错线,命名线通常更易读。
.outer {
display: grid;
grid-template-columns: [left] 10rem [main-start] 1fr [main-end] 10rem [right];
}
.card {
grid-column: left / right;
display: grid;
grid-template-columns: subgrid;
}
.card .body { grid-column: main-start / main-end; }
/* body 沿父网格正文边界对齐 */.card 跨过父级全部三列,所以 .body 能使用 main-start 与 main-end。如果把卡片改成只跨左侧栏,它就不再拥有父级正文那段轨道,相关线名不能按原设想用于子项目。先看父项目跨度,再看内部定位,顺序不能反。
局部线名和沟槽
子网格还可以在 subgrid 后给继承的线补充名称。这些名称属于子网格上下文,能让组件内部使用更贴近业务的称呼,而不必改父级版式命名。父级线名与局部线名可共同参与子项目定位。
子网格默认沿用父级对应方向的间距,但也可在子网格上覆写 gap。因此“沿用轨道”不应被说成“任何几何属性都完全锁死”;内部内容、沟槽和另一轴的轨道定义仍需要单独检查。
例如父容器的正文列两侧分别叫 main-start 与 main-end,两个不同卡片都跨正文列并设置 subgrid,它们内部标题都能对齐到这对线。若其中一个卡片只跨正文列的一半,就不能期待它内部仍有那条远端线。子网格的好处是多个组件借用同一套父级边界,减少独立网格列宽算出的细小错位;先确认父项目跨度,命名线才有意义。
若父级线名 main-start 在多个位置重复,引用时还可能需要编号来消除歧义;仅说“继承线名”不保证定位唯一。组件的局部线名应选能表达内部结构的名字,并避免和父级已有名字冲突。检查子项落点时,用开发工具显示子网格边界与线名,比拿父级数字线号猜子项范围更可靠。
容易答错的地方
- 认为子网格复制父级所有列
- 它只沿用父项目所跨的那部分轨道,父项目跨度改变时可用列也改变。
- 把父级的数字线号直接搬到子网格
- 数字编号在子网格自己的边界内重新计数,使用继承的命名线通常更稳妥。
面试官还会怎么问?
只想继承列,不继承行可以吗?
可以。列轴写 subgrid,行轴仍可设置独立的轨道列表。
子网格能增加局部命名线吗?
可以。继承父级线名之外,还能在子网格的轨道值中为已有线添加名称。
为什么子项目不能引用父级远处的线名?
子网格范围由父项目跨过的轨道决定,范围外的线不属于它所继承的那段网格。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。