卡片底部的按钮永远对不齐,你还在用 JS 量高度——CSS subgrid 今年 3 月刚进 Baseline
同一排卡片,标题一行、两行的都有,底部的按钮就参差不齐——这个对齐问题,你十有八九是用 JS 量高度或者给每张卡固定行高硬扛过去的。其实 CSS 早在 2019 年就给了原生答案:subgrid,而它在 2026 年 3 月正式进入 Baseline Widely available,Firefox 71、Safari 16、Chrome 117 起全支持,全球覆盖已超过 90%。该把那段对齐脚本删掉了。
为什么嵌套网格天生对不齐
先说清楚病根。当你给容器加 display: grid,只有它的直接子元素会成为网格项,孙元素回归普通文档流。想让卡片内部也参与网格,你通常会把卡片本身再设成 display: grid——这就是所谓的「嵌套网格」。
问题在于:嵌套网格完全独立于父网格,也彼此独立。它们各自根据自身内容计算轨道尺寸,根本感知不到旁边的兄弟卡片。于是同一行里,A 卡标题占一行、B 卡标题占两行,两张卡各自的内部行高不一样,底部自然对不齐。
过去的解法都不体面:要么用 JS 遍历所有卡片量出最大高度再统一设死,要么给每个槽位固定 min-height,内容一多就溢出。维护成本高,还容易在字体加载、窗口缩放时抖动。
subgrid 做的事:不新建轨道,直接继承
给嵌套网格的 grid-template-columns 或 grid-template-rows 设成 subgrid,关键变化就一句话:它不再生成自己的轨道列表,而是复用父网格已经定义好的轨道。
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.card {
display: grid;
grid-template-rows: subgrid; /* 继承父网格的行轨道 */
grid-row: span 3; /* 跨父网格的 3 行 */
}
父网格定义了三列,每张卡片横跨父网格的若干行;卡片内部设 grid-template-rows: subgrid 后,它的标题、正文、页脚就直接落在父网格的行轨道上。所有卡片共享同一套行高——标题对齐、正文同起点、页脚全部贴底,无论内容长短。
两个容易忽略的细节:
- 间距会继承。父网格的
gap会传进子网格,但子网格可以用自己的gap覆盖它。调试时打开 DevTools 的网格检查器,你会发现子网格线正好落在间距中央。 - 网格线编号会重置。子网格内部的第 1 条列线就是子网格自己的第一条线,不继承父网格的编号。这反而是好事:组件无论被放在父网格的哪个位置,内部编号永远一致,可复用性更强。
具名网格线也可以从父网格传下来,子网格还能额外声明自己的线名:
.card {
display: grid;
grid-template-columns: subgrid [sub-a] [sub-b] [sub-c] [sub-d];
grid-template-rows: subgrid;
}
唯一的坑:子网格维度不会自动生成隐式轨道
这是 subgrid 最容易被忽视、也最容易在生产翻车的一条规则:在设为 subgrid 的那个维度上,不会创建隐式轨道。
MDN 的例子很直白:子网格横竖都是 subgrid,内部塞 12 个元素却只有 10 个格子,多出的 2 个不会撑出新行——它们会被全部堆进最后一格。
所以实践准则是:当子项数量未知时,留一个维度用普通嵌套网格。
.card {
display: grid;
grid-template-columns: subgrid; /* 列对齐父网格 */
grid-auto-rows: minmax(100px, auto); /* 行仍按内容自动生成 */
}
删掉 grid-template-rows: subgrid,行轨道的隐式创建就恢复了,需要多少行生成多少行,只是这些行不再和父网格对齐。要不要对齐,取决于你的布局是否真的需要跨卡同步。
什么时候该用,什么时候别硬上
最佳场景其实就一类:兄弟元素之间需要内部对齐。
- 卡片列表:标题 / 正文 / 页脚跨卡对齐,这是最高频的用途;
- 表单:多个字段的 label 列宽统一,输入框起点自然对齐;
- 表格式布局:没有 table 标签、但需要列宽一致的数据行;
- 仪表盘组件:多个卡片的头部、内容、底部纵向对齐。
反过来,如果嵌套网格的布局是自成一体的,用普通独立网格更简单,没必要引入 subgrid。
浏览器支持不用再纠结:Chrome 117+、Firefox 71+、Safari 16+、Edge 117+,Subgrid 自 2026 年 3 月起 Baseline Widely available,生产可用。老浏览器用 @supports (grid-template-rows: subgrid) 做特性检测,降级到 Flexbox 即可——虽然失去跨卡对齐,但布局不会崩。
下一步
打开你项目里那段「遍历卡片量高度」的代码,先别急着删。用一层 @supports 包住新的 subgrid 写法:
@supports (grid-template-rows: subgrid) {
.card { display: grid; grid-template-rows: subgrid; grid-row: span 3; }
}
跑一遍网格检查器,确认对齐符合预期,再把旧的 JS 对齐逻辑摘掉。一次改一个卡片列表,风险最小、收益最直观。
评论区
登录后可评论。