可变长度的标题
每张卡片的说明文字长度都可能不同。
查看详情我在做一组“标题、说明、按钮”结构的卡片时,最先发现的不是文字溢出,而是按钮上下不齐:短标题的卡片很快结束,长标题的卡片却把说明和按钮往下推。让每张卡片自己写一套 grid-template-rows 只能让单张卡片好看,不能让兄弟卡片共享行高。
解决这类问题的关键是把卡片设为父网格的跨行子项,再用 grid-template-rows: subgrid 继承父网格轨道。这样标题、正文和操作区参与的是同一组行尺寸计算,内容长度不同也能保持横向对齐。
subgrid 只能继承父级网格的轨道,不能脱离父网格单独生效。subgrid 当成万能的等高技巧。假设卡片列表本身是两列网格,每张卡片又在内部写了三行。内部网格是独立格式化上下文,第一张卡片的标题行和第二张卡片的标题行不会互相影响,所以只要某个标题换行,后面的说明和按钮就会出现高低差。
可变长度的标题
每张卡片的说明文字长度都可能不同。
查看详情
如果 .card 自己使用 grid-template-rows: auto 1fr auto,它只能在本卡片范围内拉伸中间行;相邻卡片不会使用同一条标题基线。问题不在于 1fr 写错,而在于网格的作用域被切开了。
把父容器定义为网格后,让每张卡片跨过父网格的三行,再在卡片上打开子网格。下面的示例只共享行,不共享列;卡片的列宽仍由父容器的两列决定。
.cards {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-rows: auto auto auto;
gap: 16px;
}
.card {
/* 跨过父网格的三行,才能继承这三条行轨道。 */
grid-row: span 3;
display: grid;
/* 让标题、说明和按钮加入父网格的行尺寸计算。 */
grid-template-rows: subgrid;
gap: 0;
padding: 20px;
border: 1px solid #d8dee9;
border-radius: 12px;
}
.card h3,
.card p,
.card a {
/* 每个直接子项占据一条共享轨道,避免按钮被内容挤散。 */
margin: 0;
}
.card a {
align-self: end;
color: #1769aa;
}
这里最容易漏掉的是 grid-row: span 3。subgrid 的行数取决于卡片在父网格中跨过的行范围;如果卡片只占一行,内部就没有三条父级轨道可继承。父级的 gap 也会参与子网格的布局,因此不要为了“补齐间距”在卡片里重复加一套相同的行间距。

卡片内部的直接子元素会按网格自动放入三条行。为了让代码更不容易被后续插入的装饰节点打乱,可以显式写出行位置;例如把标题放在第一行、说明放在第二行、链接放在第三行。这样改颜色、加图标时,不会误把一个新元素塞进错误的轨道。
.card h3 { grid-row: 1; }
.card p { grid-row: 2; }
.card a { grid-row: 3; }
/* 仅调整卡片内部留白,不重新定义共享行的高度。 */
.card p {
padding-block: 12px;
color: #52606d;
}
如果标题过长,父网格的第一行会被最长标题撑高,其他卡片的第一行随之对齐;如果说明文字很多,第二行同理。这个结果和“所有卡片固定高度”不同:卡片仍然会随内容增长,且不会把文字硬裁掉。
| 现象 | 优先检查 | 处理方式 |
|---|---|---|
| 按钮仍然高低不齐 | 卡片是否跨过三行 | 补上 grid-row: span 3 |
| subgrid 没有作用 | 父级是否为 Grid | 确认父级有 display: grid |
| 内容被裁切 | 是否误设固定高度 | 避免 height,用自动行高和内边距 |
| 间距突然变大 | 父级与子级是否重复设置 gap | 保留一层负责行间距 |

MDN 将 subgrid 标为现代浏览器中已经广泛可用的特性,但项目仍应以目标浏览器矩阵为准。它必须建立在真正的父级 Grid 上;绝对定位、布局隔离等情况会让元素无法继续作为父网格的子网格。
如果需要支持不具备 subgrid 的环境,可以先保留卡片可读性,再牺牲跨卡片的精确行对齐:
.card {
/* 默认方案保持内容可读,旧浏览器也能正常显示。 */
display: grid;
grid-template-rows: auto 1fr auto;
}
@supports (grid-template-rows: subgrid) {
.card {
/* 支持 subgrid 时再接入父网格的三条共享行。 */
grid-row: span 3;
grid-template-rows: subgrid;
}
}
这个 fallback 的目标是“能用且不乱”,不是伪造完全相同的视觉结果。上线前用目标浏览器检查三件事:父级是否真的创建 Grid、卡片是否跨过所需行数、以及不支持时按钮是否仍可点击且没有被固定高度截断。
不能。它要求子网格来自父级 Grid 的网格项关系;无关容器之间应调整 DOM 结构,或采用共享父网格、固定轨道等方案。
通常是因为元素没有跨过父级对应的多行,或者父级并不是 Grid。先检查父级的行定义和卡片的 grid-row 范围。
内容长度变化明显时优先考虑 subgrid;固定高度适合信息量严格受控的组件。固定高度更容易造成溢出和无障碍阅读问题。
Go 泛型编译报 cannot infer type 如何补充类型参数