Grid 对齐、简写与 Subgrid
先分清两组对齐属性
Grid 的对齐属性容易混淆,记住两个维度就不会错:
| 前缀 | 控制方向 | 含义 |
|---|---|---|
justify-* | 行内轴(通常是水平) | 左右 |
align-* | 块轴(通常是垂直) | 上下 |
*-items | 容器上设置,控制每个 Item 在自己格子内的位置 | 对齐内容 |
*-self | Item 上设置,覆盖容器的 *-items | 单独例外 |
*-content | 容器上设置,控制整个网格在容器内的位置 | 对齐轨道 |
🧠 一句话区分:
items管「东西在格子里怎么放」,****content管「格子在容器里怎么放」。
对齐单元格中的 Item
.container {
justify-items: center; /* 行内轴,通常是水平方向 */
align-items: center; /* 块轴,通常是垂直方向 */
place-items: center; /* 简写:align-items justify-items */
}
常用值:start、end、center、stretch(默认值)。
单独覆盖某个元素:
.item {
justify-self: end;
align-self: start;
place-self: start end; /* align-self justify-self */
}
实例:表单里标签右对齐、输入框左对齐:
.form {
display: grid;
grid-template-columns: max-content minmax(0, 1fr);
gap: 12px 16px;
align-items: center;
}
.form label {
justify-self: end; /* 标签靠右,贴着输入框 */
}
对齐整个网格
只有当容器尺寸大于所有轨道总和时,这组属性才有可见效果:
.container {
display: grid;
grid-template-columns: repeat(3, 100px); /* 固定宽,会剩下空间 */
width: 600px;
justify-content: space-between; /* 网格整体水平分布 */
align-content: center; /* 网格整体垂直居中 */
place-content: center space-between;
}
可用值:start、end、center、stretch、space-between、space-around、space-evenly。
⚠️ 如果你的列都是
1fr,轨道已经吃满容器,那么justify-content看不出任何效果。这是「写了不生效」最常见的原因。
对齐属性速查表
| 我想做的事 | 写在哪里 | 属性 |
|---|---|---|
| 所有 Item 在格子内垂直居中 | 容器 | align-items: center |
| 所有 Item 不要被拉高 | 容器 | align-items: start |
| 单个 Item 靠右 | Item | justify-self: end |
| 单个 Item 完全居中 | Item | place-self: center |
| 完美居中一个子元素 | 容器 | place-items: center |
| 固定宽的列在容器里均匀散开 | 容器 | justify-content: space-between |
| 整个网格在高容器里垂直居中 | 容器 | align-content: center |
grid 简写
grid 可以一次性设置显式与隐式网格相关属性,但语法密集,而且会把未列出的属性重置为初始值。
/* 行:自动流,每行 120px;列:3 等分 */
.container {
grid: auto-flow 120px / repeat(3, 1fr);
}
/* 等价于 */
.container {
grid-auto-flow: row;
grid-auto-rows: 120px;
grid-template-columns: repeat(3, 1fr);
}
还可以把区域和尺寸写在一起:
.page {
grid:
"header header" auto
"nav main" 1fr
"footer footer" auto
/ 200px 1fr;
}
🛠️ 业务代码中建议优先使用单独属性。简写最大的坑是:你只想改列定义,却顺手把
grid-auto-rows等属性静默清空了。
subgrid
subgrid 让子网格复用父网格的轨道,而不是建立一套独立轨道。
它解决什么问题
三张卡片,标题行数不同(一行 / 两行 / 一行)。普通嵌套 Grid 下,每张卡片自己算行高,正文和按钮的位置就对不齐了。subgrid 可以让三张卡片共用同一套行轨道,标题区、正文区、按钮区一条线对齐。
<ul class="cards">
<li class="card">
<h3>短标题</h3>
<p>正文……</p>
<button>查看</button>
</li>
<li class="card">
<h3>一个会换行的很长的标题</h3>
<p>正文……</p>
<button>查看</button>
</li>
</ul>
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* 关键:父级定义三行轨道(标题 / 正文 / 按钮)*/
grid-template-rows: auto 1fr auto;
gap: 16px;
}
.card {
display: grid;
grid-template-rows: subgrid; /* 复用父级的行轨道 */
grid-row: span 3; /* 必须明确占据 3 行 */
gap: 8px;
}
使用要点
- 子网格本身必须是父 Grid 的 Grid Item。
- 必须用
grid-row: span N/grid-column: span N明确占据多个轨道,否则subgrid无轨道可用。 - 可以只对行或只对列使用,也可以两者都用。
- 子网格可以有自己的
gap,不写则继承父级。 - 父级的命名网格线会被子网格继承,可以直接引用。
兼容性回退
.card {
display: grid;
grid-template-rows: auto 1fr auto; /* 回退:卡片内部自己对齐 */
}
@supports (grid-template-rows: subgrid) {
.card {
grid-template-rows: subgrid;
grid-row: span 3;
}
}
回退方案保证卡片内部按钮仍在底部,只是卡片之间不一定严格对齐。使用前建议结合目标浏览器范围确认支持情况。