跳到主要内容

Grid 对齐、简写与 Subgrid

先分清两组对齐属性

Grid 的对齐属性容易混淆,记住两个维度就不会错:

前缀控制方向含义
justify-*行内轴(通常是水平左右
align-*块轴(通常是垂直上下
*-items容器上设置,控制每个 Item 在自己格子内的位置对齐内容
*-selfItem 上设置,覆盖容器的 *-items单独例外
*-content容器上设置,控制整个网格在容器内的位置对齐轨道

🧠 一句话区分:items 管「东西在格子里怎么放」,****content 管「格子在容器里怎么放」。

对齐单元格中的 Item

.container {
justify-items: center; /* 行内轴,通常是水平方向 */
align-items: center; /* 块轴,通常是垂直方向 */
place-items: center; /* 简写:align-items justify-items */
}

常用值:startendcenterstretch默认值)。

单独覆盖某个元素:

.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;
}

可用值:startendcenterstretchspace-betweenspace-aroundspace-evenly

⚠️ 如果你的列都是 1fr,轨道已经吃满容器,那么 justify-content 看不出任何效果。这是「写了不生效」最常见的原因。

对齐属性速查表

我想做的事写在哪里属性
所有 Item 在格子内垂直居中容器align-items: center
所有 Item 不要被拉高容器align-items: start
单个 Item 靠右Itemjustify-self: end
单个 Item 完全居中Itemplace-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;
}
}

回退方案保证卡片内部按钮仍在底部,只是卡片之间不一定严格对齐。使用前建议结合目标浏览器范围确认支持情况。