CSS 网格布局(Grid Layout)是 CSS 中最强大的二维布局系统。一句话概括它的定位:Flexbox 管一维(一行或一列),Grid 管二维(行和列同时控制)。页面主结构、卡片画廊、仪表盘、图片墙——凡是「横竖都要对齐」的场景,Grid 都是首选。

本文从作用、使用场景、核心语法到实战技巧,带你系统掌握 Grid 布局,所有代码可直接复制使用。

CSS 网格布局概念图:发光的 3x3 蓝紫色网格面板
Grid:让行与列同时可控的二维布局系统

网格布局的作用

在 Grid 出现之前,做复杂的页面结构要靠 float、定位甚至表格 hack,代码冗长还难维护。Grid 的核心价值有三点:

  • 二维同时控制:一个容器同时定义行轨道和列轨道,元素可以精确落在「第几行第几列」。
  • 结构与内容分离:用 grid-template-areas 画ASCII地图即可排版,HTML 顺序不用动,换断点时只改 CSS。
  • 代码量断崖式下降:过去需要嵌套多层 div + 媒体查询的布局,现在 3~5 行 CSS 搞定。
💡 理解要点:Grid 由「容器(grid container)」和「项目(grid item)」组成,容器上定义轨道(行/列),项目决定自己占哪几格。

Grid 与 Flexbox:怎么选?

两者不是替代关系,而是互补。判断标准很简单:内容排成一条线用 Flex,排成一片面用 Grid。

左侧一维横排项目示意 Flex,右侧二维矩阵示意 Grid
左:Flex 一维轴线;右:Grid 二维矩阵
对比项 Flexbox Grid
维度 一维(行或列) 二维(行 + 列)
布局起点 内容决定布局(content-first) 布局决定内容位置(layout-first)
典型场景 导航栏、按钮组、单行卡片 页面骨架、画廊、表格型界面
跨行/跨列 不支持 span / 区域命名原生支持
空隙控制 gap gap(行列分别设置)
ℹ️
组合使用
实际项目中最常见的模式:外层用 Grid 搭页面骨架和卡片网格,卡片内部的小排版(标题+按钮对齐)用 Flex。两者搭配,各取所长。

核心语法:定义你的第一个网格

三行代码就能建立一个 3 列等宽、带 16px 间距的网格:

css basic-grid.css
.container {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 16px;
}
等距视角的网格轨道示意图,行列轨道与单元格间距清晰可见
轨道(track)与间距(gap):Grid 的两个基本构件

必须记住的 4 个容器属性

属性 作用 示例
display: grid 开启网格容器 直接写在父元素上
grid-template-columns 定义列轨道 200px 1fr 1fr
grid-template-rows 定义行轨道 60px 1fr 40px
gap 行/列间距 gap: 16px 24px

fr 单位:Grid 最好用的发明

fr(fraction)表示「剩余空间的一份」。与百分比不同,fr 会自动扣除 gap 间距,配合固定宽度非常好算:

css
/* 侧栏固定 240px,主区与侧栏按 2:1 瓜分剩余空间 */
.layout {
	display: grid;
	grid-template-columns: 240px 1fr;
	/* 更细的分配: */
	grid-template-columns: 240px minmax(0, 2fr) 1fr;
}
💡 小技巧:1fr 约等于「自适应剩余宽度」,写布局时优先用 fr,少用百分比 + calc()。

典型使用场景

场景 1:响应式卡片画廊(无需媒体查询)

auto-fit + minmax 是 Grid 最经典的组合:卡片最小 220px,容器变窄时自动减少列数,变宽时自动增列,一行 CSS 完成响应式:

css card-gallery.css
.gallery {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 20px;
}

场景 2:页面骨架(Holy Grail 布局)

用 grid-template-areas 画一张「地图」,语义直观,移动端重排只需改地图:

css page-layout.css
.page {
	display: grid;
	grid-template-areas:
		"header header header"
		"nav    main   aside"
		"footer footer footer";
	grid-template-columns: 200px 1fr 240px;
	grid-template-rows: 60px 1fr 48px;
	min-height: 100vh;
	gap: 12px;
}
.header { grid-area: header; }
.nav    { grid-area: nav; }
.main   { grid-area: main; }
.aside  { grid-area: aside; }
.footer { grid-area: footer; }

/* 移动端:改地图即可,HTML 不动 */
@media (max-width: 768px) {
	.page {
		grid-template-areas:
			"header"
			"nav"
			"main"
			"aside"
			"footer";
		grid-template-columns: 1fr;
	}
}

场景 3:图片不规则拼贴

让某个项目跨行跨列,用 grid-row / grid-column 的 span 即可做出杂志风拼贴:

css
.mosaic {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	grid-auto-rows: 180px;
	gap: 10px;
}
.mosaic .feature {
	grid-column: span 2;
	grid-row: span 2;
}

场景 4:仪表盘 / 后台表格型界面

统计卡片、图表区块这类「横竖都要对齐」的界面,Grid 比 Flex + 换行可控得多——Flex 换行后每行高度独立,无法保证纵向对齐,而 Grid 天然保证行轨道与列轨道对齐。

实战技巧清单

技巧 1:auto-fill 与 auto-fit 的区别

  • auto-fill:尽量塞满轨道,空轨道保留占位。
  • auto-fit:空轨道坍缩为 0,已有项目被拉伸填满整行。
  • 卡片少的时候想拉伸铺满 → 用 auto-fit;想保持格子节奏 → 用 auto-fill。

技巧 2:minmax(0, 1fr) 解决内容撑爆

Grid 项目默认 min-width: auto,长文本/代码会把列撑破。把最小值显式设为 0 即可让内容正常收缩:

css
.row {
	display: grid;
	grid-template-columns: 1fr minmax(0, 2fr) 1fr;
	/* 或者统一处理: */
}
.row > * {
	min-width: 0;
}

技巧 3:grid-auto-flow: dense 自动补洞

有跨格项目时网格会出现空洞,dense 会让后续小项目自动回填空隙,适合图片流、瀑布位:

css
.grid {
	grid-auto-flow: row dense;
}
⚠️
注意
dense 会打乱 DOM 顺序的视觉呈现,影响键盘 Tab 焦点顺序,纯展示型网格再用。

技巧 4:隐式网格与 grid-auto-rows

grid-template-* 只定义「显式轨道」,超出部分进入隐式轨道,默认高度由内容决定。用 grid-auto-rows 给隐式行统一设定基准:

css
.grid {
	grid-template-columns: repeat(3, 1fr);
	grid-auto-rows: 120px; /* 第 4 行及以后自动 120px */
}

技巧 5:容器级与项目级对齐

层级 属性 作用
容器 justify-items / align-items 所有格子内容的默认对齐
容器 justify-content / align-content 整个网格在容器内的分布
项目 justify-self / align-self 单个项目在自己格子里的对齐

技巧 6:subgrid 对齐嵌套结构

卡片内部字段(标题/正文/按钮)想跨卡片纵向对齐?让子元素继承父网格轨道:

css
.card {
	display: grid;
	grid-row: span 3;        /* 卡片占父网格 3 行 */
	grid-template-rows: subgrid; /* 内部直接复用父轨道 */
}
💡 兼容性:subgrid 目前 Chrome / Firefox / Safari 新版均已支持,老浏览器需降级为固定行高方案。

总结

布局思维从「内容怎么排」升级为「先画网格,再放内容」——这正是 Grid 让 CSS 布局工程化的关键一步。
  • 一维用 Flex,二维用 Grid,骨架用 Grid、内部用 Flex 是最佳拍档。
  • 记住三板斧:display: grid + repeat() + minmax(),80% 的布局需求即可覆盖。
  • 响应式优先尝试 repeat(auto-fit, minmax(220px, 1fr)),很多场景真的不需要媒体查询。
  • 内容撑爆列时,第一反应写 min-width: 0 或 minmax(0, 1fr)。