序:Flex 解决了一半的问题
上一篇我们讲了 Flex 布局。Flex 很强大,但它本质上是一维布局——它要么控制行,要么控制列,无法同时精确管理两者。
当你需要做一个真正的二维网格:5 行 7 列,某些格子跨 2 列,某些格子跨 3 行,第 3 行整体偏移……Flex 就捉襟见肘了。
这就是 CSS Grid Layout 存在的意义。
Grid 是 CSS 历史上第一个真正的二维布局系统,2017 年被所有主流浏览器全面支持。如果说 Flex 是布局的瑞士军刀,那 Grid 就是精密铣床——它用一套声明式的语法,把整个页面变成一个你可以精确控制的网格。
一、Grid vs Flex:什么时候用哪个?
这是开发者最常问的问题。答案其实很简单:
| 对比维度 | Flex(一维) | Grid(二维) |
|---|---|---|
| 维度 | 一次控制一个方向 | 同时控制行和列 |
| 设计思路 | 从内容出发,空间自适应 | 从容器出发,先画网格再放内容 |
| 适合场景 | 导航栏、按钮组、工具条 | 页面整体骨架、复杂网格、仪表盘 |
| 对齐控制 | 主轴/交叉轴对齐 | 行对齐 + 列对齐,独立控制 |
| 换行行为 | flex-wrap 换行后行间关系断裂 |
网格轨道固定,项目跨格精确可控 |
| 学习曲线 | 平缓 | 稍陡,但概念清晰 |
一句话原则:Flex 用于组件内部的微观布局,Grid 用于页面级别的宏观布局。 两者不是替代关系,而是互补。
二、核心概念:网格的六个术语
学 Grid 最大的门槛不是语法,是术语。搞懂这六个词,后面的一切都顺理成章。
网格六要素
| 术语 | 英文 | 说明 |
|---|---|---|
| 容器 | Grid Container | display: grid 激活的元素 |
| 项目 | Grid Item | 容器的直接子元素 |
| 行轨道 | Row Track | 网格的水平线之间的空间 |
| 列轨道 | Column Track | 网格的垂直线之间的空间 |
| 单元格 | Cell | 行和列交叉形成的最小单位 |
| 网格线 | Grid Line | 行和列的分界线,编号从 1 开始 |
一张图理解:
1 | 列线1 列线2 列线3 列线4 |
关键点:网格线编号从 1 开始,从左到右、从上到下递增。一个 3 列的网格有 4 条列线。后面的 grid-column 和 grid-row 属性就是用线号来定位项目的。
三、定义网格:容器属性详解
3.1 grid-template-columns / grid-template-rows:画格子
这是 Grid 最核心的属性——定义列和行的轨道尺寸。
1 | .container { |
上面的代码画出了一个 3 列 3 行 的网格:第一列固定 200px,后两列等分剩余空间;第一行固定 80px,中间行自适应,最后一行 60px。
轨道尺寸单位一览:
| 值 | 含义 | 示例 |
|---|---|---|
px / % |
固定值或百分比 | 200px、50% |
fr |
按比例分配剩余空间 | 1fr 2fr(1:2 分配) |
auto |
由内容决定大小 | auto 1fr |
minmax(min, max) |
最小值和最大值之间 | minmax(200px, 1fr) |
repeat(n, value) |
重复简化写法 | repeat(3, 1fr) 等价于 1fr 1fr 1fr |
fit-content(limit) |
内容尺寸但不超限 | fit-content(300px) |
最实用的组合:repeat(auto-fill, minmax(200px, 1fr)) —— 自动按 200px 最小宽度排列尽可能多的列,剩余空间均分。这是响应式卡片网格的最佳写法。
3.2 gap:网格间距
和 Flex 一样,Grid 也支持 gap,且语义更明确——可以分别设置行列间距。
1 | .container { |
3.3 grid-template-areas:用名字画布局
这是 Grid 最直觉、最强大的特性。你可以用文字”画”出页面布局:
1 | .container { |
看到没?grid-template-areas 的每一行对应网格的一行,每个名字对应一个单元格。相同名字表示项目跨越多格。这种写法让布局意图一目了然,是 Grid 的灵魂特性。
规则:
- 同一名字必须形成矩形区域,不能出现 L 形或散点
- 用
.表示空单元格 - 区域名必须在项目上用
grid-area引用
3.4 justify-items / align-items:单元格内对齐
控制每个项目在各自单元格内的对齐方式。
1 | .container { |
| 值 | 效果 |
|---|---|
stretch(默认) |
拉伸填满单元格 |
start |
靠单元格起点 |
end |
靠单元格终点 |
center |
单元格内居中 |
简写:place-items: align-items justify-items,如 place-items: center center。
3.5 justify-content / align-content:整个网格在容器内的对齐
当网格总尺寸小于容器时,控制整个网格的对齐。
1 | .container { |
简写:place-content: align-content justify-content。
3.6 grid-auto-flow:自动排列方向
当项目没有显式指定位置时,Grid 按什么方向自动排列?
1 | .container { |
| 值 | 效果 |
|---|---|
row(默认) |
按行排列,放满一行再换行 |
column |
按列排列,放满一列再换列 |
dense |
紧凑排列,尝试用前面的空位填充(可能打乱顺序) |
dense 模式适合瀑布流/图片墙等不关心顺序的场景,能减少视觉空洞。但注意它可能改变项目的 DOM 顺序与视觉顺序的对应关系。
四、放置项目:项目属性详解
4.1 grid-column / grid-row:用线号定位
这是最精确的定位方式——用网格线编号指定项目的起止位置。
1 | .item { |
语法:grid-column: start / end,grid-row: start / end。
跨数简写:用 span 关键字表示跨越的轨道数。
1 | .item { |
4.2 grid-area:用名字定位
配合 grid-template-areas 使用,也可以作为 grid-row-start / grid-column-start / grid-row-end / grid-column-end 的简写。
1 | /* 方式一:引用区域名 */ |
4.3 justify-self / align-self:单个项目对齐
覆盖容器的 justify-items / align-items,让单个项目”开小差”。
1 | .container { justify-items: stretch; } |
简写:place-self: align-self justify-self。
4.4 项目属性速查表
| 属性 | 作用 | 常用值 |
|---|---|---|
grid-column |
列方向起止位置 | 1 / 3、1 / span 2 |
grid-row |
行方向起止位置 | 2 / 4、span 3 |
grid-area |
区域名或线号简写 | header、2 / 1 / 4 / 3 |
justify-self |
单个项目水平对齐 | start、end、center、stretch |
align-self |
单个项目垂直对齐 | start、end、center、stretch |
五、实战案例(三个高频场景)
案例一:经典页面骨架
这是 Grid 最经典的用法——用 grid-template-areas 一眼看清页面结构。
1 | <div class="page"> |
1 | .page { |
换行 grid-template-areas 就完成了移动端适配,不需要改 HTML 结构。这就是 Grid 的威力。
案例二:自动响应式卡片网格
1 | .card-grid { |
repeat(auto-fill, minmax(260px, 1fr)) 的魔法在于:
- 屏幕宽时自动放更多列
- 屏幕窄时自动减少列数
- 每列最小 260px,剩余空间均分
- 零媒体查询,纯 CSS 实现响应式
案例三:跨格仪表盘布局
1 | .dashboard { |
用 Flex 实现这个布局需要大量嵌套和 hack,而 Grid 只需声明线号,精确且直观。
六、常见陷阱与最佳实践
6.1 陷阱一:fr 不是百分比
1 | /* 以下两者行为不同 */ |
fr 分配的是扣除固定轨道和 gap 之后的剩余空间,所以不会因为 gap 导致溢出。推荐用 fr 而非 %。
6.2 陷阱二:auto-fill vs auto-fit
1 | repeat(auto-fill, minmax(200px, 1fr)); /* 创建空轨道占位 */ |
| 模式 | 项目少时的表现 |
|---|---|
auto-fill |
保留空列位置,项目不会拉伸 |
auto-fit |
空列折叠,项目拉伸填满整行 |
经验:卡片网格用 auto-fill(保持卡片宽度一致),单行按钮组用 auto-fit(拉伸填满)。
6.3 陷阱三:隐式网格的尺寸
当项目超出 grid-template-rows/columns 定义的范围时,Grid 会自动创建隐式轨道。
1 | .container { |
不加 grid-auto-rows,隐式行的高度由内容撑开,可能导致行高不一致。记得设置 grid-auto-rows。
6.4 陷阱四:dense 模式的顺序问题
1 | grid-auto-flow: row dense; |
dense 会尝试用前面的空位填充后续项目,可能导致视觉顺序与 DOM 顺序不一致。这会影响:
- 键盘 Tab 导航顺序
- 屏幕阅读器朗读顺序
无障碍要求高的页面慎用 dense。
6.5 最佳实践速查表
| 需求 | 代码 |
|---|---|
| 等分 N 列 | grid-template-columns: repeat(N, 1fr) |
| 响应式卡片 | repeat(auto-fill, minmax(260px, 1fr)) |
| 固定侧边栏 + 自适应主区 | grid-template-columns: 240px 1fr |
| 跨列项目 | grid-column: 1 / -1(跨满,-1 是最后一条线) |
| 行列间距 | gap: 16px |
| 区域命名布局 | grid-template-areas: "header header" "nav main" |
| 单元格内居中 | place-items: center |
| 网格整体居中 | place-content: center |
七、Flex + Grid 协作:最佳搭档
实际项目中,Flex 和 Grid 经常配合使用。一个典型模式:
1 | /* 外层用 Grid 做页面骨架 */ |
原则:Grid 管宏观骨架,Flex 管微观排列。各司其职,代码清晰。
八、总结
Grid 的学习曲线比 Flex 陡一些,但它的表达能力是质变级的——用几行 CSS 就能描述出过去需要大量嵌套和 hack 才能实现的二维布局。
记忆框架:
- 容器调
display: grid - 画格子用
grid-template-columns/rows - 命名布局用
grid-template-areas - 间距用
gap - 项目定位用
grid-column/row或grid-area - 对齐用
place-items(单元格内)和place-content(整体)
掌握这六步,你就拥有了 CSS 二维布局的终极武器。
延伸阅读
- MDN: CSS Grid Layout
- CSS-Tricks: A Complete Guide to Grid
- Grid Garden —— 通过游戏学习 Grid 布局
- Grid by Example —— Rachel Andrew 的 Grid 示例合集
本文写于 2026 年 6 月 27 日,所有代码示例均基于最新 CSS Grid Level 1 规范,兼容 Chrome、Firefox、Safari、Edge 最新版本。