第六章:Grid------二维布局的终极方案
上一章我们学习了 Flex,它擅长处理一维布局(要么排成一行,要么排成一列)。但现实中的页面往往是二维的------既有行,又有列。比如:
- 图片墙(多行多列)
- 复杂后台仪表盘
- 杂志风格的卡片布局
- 整体页面框架(侧边栏 + 主内容 + 多个区域)
这些需求,Flex 能做,但往往要嵌套多层,代码变得复杂。而 Grid 布局 ,就是为了直接处理二维网格而生的。

6.1 Flex 的局限:为什么还需要 Grid?
flex-wrap: wrap 确实可以让 Flex 项目换行,产生多行的效果,看起来像二维。
那为什么官方和教程还坚持说 Flex 是 一维 ,Grid 才是 二维 呢?
核心区别在于:你是如何控制"换行后那些行"的。
1. Flex 的"换行"是无奈之举,它不关心"行"的关系
当 Flex 换行后,每一行都是一个独立的、新的 Flex 容器。行与行之间几乎没有关系。
- 你看不到列 :第一行的第一个元素,和第二行的第一个元素,在垂直方向上没有任何对齐关系。它们只是各自被自己的行居中、拉伸或排列。
- 你无法控制"行"的整体结构:你不能说"让所有行的高度比例是 1:2:1",也不能说"让第二行的元素整体向下移动10px"。
打个比方:Flex 换行就像一排人并排站,站不下了就自然到后面再起一排。 后面那排人不会刻意对齐前面那排人的位置,每排都是独立重新排列。
2. Grid 的"二维"是主动设计,它同时规划了行和列
Grid 在声明时,就同时画好了行轨道 和列轨道,形成一个真正的"表格"结构。
- 列是真实存在的:所有行里的元素,都会严格对齐到你定义的那些列线上。
- 你可以整体控制:你可以说"所有行的行高都是1fr"、"第二行的高度是100px"、"让第一个元素横跨两行两列"。
打个比方:Grid 就像在一张画好格子的棋盘上下棋。 每个格子都有固定的坐标(第几行,第几列),你可以把棋子放在任何一个格子里,或者让一个棋子占多个格子。

用代码直观对比:实现一个"照片墙"
假设我们有6个方块,希望它们排成2行3列,每个格子大小一致。
用 Flex (换行) 实现:
css
.flex-container {
display: flex;
flex-wrap: wrap;
}
.flex-item {
width: 33.333%; /* 必须手动算宽度,强迫成3列 */
/* 或者用 flex: 1 0 33.333% */
}
问题来了:
- 你想让第二行的三个方块,在垂直方向上和第一行严格对齐吗?它们本来就在同一列上,但因为Flex没有"列"的概念,其实是靠宽度硬算出来的,容易因边框、边距产生偏差。
- 你想让第一行的高度是100px,第二行是200px?Flex做不到。 它会根据内容撑开,你无法单独控制某一行的行高。
用 Grid 实现:
css
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* 明确3列 */
grid-auto-rows: minmax(100px, auto); /* 行高默认自动 */
}
/* 想让第一行高100px,第二行高200px? */
.grid-container {
grid-template-rows: 100px 200px; /* 直接声明! */
}
清晰明了: 列是列,行是行,你可以随意操控整个网格结构。

一张表格彻底说清楚
| 特性 | Flexbox (一维) | Grid (二维) |
|---|---|---|
| 控制重心 | 控制 项目本身 在主轴上的分布、对齐、顺序 | 控制 容器结构,先画好行和列的轨道 |
| 换行后的关系 | 换行后,行与行独立,无法对齐不同行的项目 | 行和列从一开始就定义好了,所有项目按坐标对齐 |
| 能否单独控制某一行的高度? | 不能 。所有行的高度由内容决定,你只能统一设置 align-content |
能 。用 grid-template-rows 精确指定每一行的高度 |
| 能否让一个元素同时跨越多行多列? | 不能。Flex 项目永远是一条直线上的一个点 | 能 。grid-row: span 2; grid-column: span 2 |
| 最适用场景 | 导航栏、列表项、表单内元素对齐(内容数量不确定) | 整体页面布局、复杂卡片墙、仪表盘(结构确定) |
总结:一句话区分
- Flex 的一维 :它只关心一条线 上的排列。即使换行产生了多条线,它也不认为这些线组成了一个平面,每条线依然各行其是。
- Grid 的二维 :它一上来就声明这是一个平面。先有行和列的网格框架,再把项目放进去。
所以,正确的理解是:
Flex 可以模拟 出二维的效果(通过换行和固定宽度),但它缺乏控制二维结构的能力(对齐行与行、控制特定行高、元素跨行跨列)。而 Grid 天生就为二维设计,这些能力是内置的。
学完 Flex 再学 Grid,你最大的感受就是:"以前用 Flex 绞尽脑汁凑出来的复杂布局,用 Grid 简直是降维打击。"

6.2 核心概念详解:Grid 网格布局 ------ 像棋盘、像表格、像渔网
整体画面 :想象你在下一盘围棋 / 做一个Excel表格 。
横线和竖线交织成一张"网",网上的每一个小"格子"就是一个独立的位置。
你可以让一个东西只占一个格子,也可以让它占连续的好几个格子。
一、为什么叫"网格"(Grid)?
因为它的样子就像一张"网"+"格"
- 渔网:有横的绳子、竖的绳子,交织在一起
- Excel表格:横线竖线切割出来的表格
"网" 指的是横竖交错的线(网格线)
"格" 指的是线围出来的一个个小空间(单元格)
所以"网格"="网状的格子结构"。你脑海里应该浮现的是:一张由横线和竖线编织成的网,网上全是整齐的小格子。

二、网格线(grid lines)------ 棋盘上的"坐标线"
画面感:就像一张坐标纸,有横着的线和竖着的线,线就是边界和编号。
网格线是 Grid 的"骨架"。一个 3×3 的网格,有 4 条纵向网格线(列线)和 4 条横向网格线(行线)。
竖线编号:1 2 3 4
| | | |
横线1 ------ +------------+------------+------------+
| | | |
横线2 ------ +------------+------------+------------+
| | | |
横线3 ------ +------------+------------+------------+
| | | |
横线4 ------ +------------+------------+------------+
项目可以指定从哪条线开始,到哪条线结束。
通俗理解 :你可以告诉一个元素"从第2条竖线开始,到第4条竖线结束",它就知道自己该占多宽了。就像告诉一个人"从A街道走到C街道"。
为什么叫"线"?
因为就是字面意思------画出来的线。在真实世界里:
- 你在纸上画表格,是不是先画横线 和竖线?
- 围棋棋盘上,是不是有横线和竖线?
- 建筑图纸上,是不是用线来划分区域?
Grid里的"线"就是你划分布局时看不见但真实存在的边界。第1条线、第2条线、第3条线......就像尺子上的刻度线。
为什么不是"边界"而是"线"?
因为"边界"强调的是"边缘",而"线"强调的是位置编号------你可以说"从第2条线到第4条线",就像说"从2楼到4楼"。

三、为什么叫"行"(row)和"列"(column)?
这是从现实世界借来的概念
| 场景 | 行 | 列 |
|---|---|---|
| Excel表格 | 横着的一排(1行、2行) | 竖着的一排(A列、B列) |
| 电影院 | 第1排、第2排(横着坐一排人) | 第1列、第2列(竖着的一串座位) |
| 教室座位 | 第1行同学(左右一排) | 第1列同学(上下一条) |
| 报纸排版 | 一行文字(从左到右) | 一列文字(从上到下) |
记忆口诀 :
行 = 横行 = 横着走(左右方向)
列 = 队列 = 竖着排队(上下方向)
在Grid里完全沿用这个现实世界的叫法,因为所有人类都已经理解什么是行和列了。

四、网格轨道(grid tracks)------ 一整条"行通道"或"列通道"
画面感 :不是单个格子,而是一整排格子连起来的那条"通道"。
就是"行"或"列"。定义网格时,你用 grid-template-columns 和 grid-template-rows 来指定每条轨道的大小。
第1行轨道 ------------------------------------------------
第2行轨道 ------------------------------------------------
第3行轨道 ------------------------------------------------
通俗理解:轨道就是"车道"。每一行就像一条横向车道,每一列就像一条纵向车道。你告诉系统"车道有多宽",所有车(子元素)就沿着它走。
为什么叫"轨道"(track)?
这个比喻来自"火车轨道"或"田径跑道"
想象一个田径跑道:
- 第1跑道、第2跑道、第3跑道......
- 每条跑道是一整条从头到尾的通道
- 跑道上的运动员(子元素)在这条通道里移动
轨道 ≠ 单元格
- 单元格是"一个格子"(一个小方块)
- 轨道是"一整行"或"一整列"(一排格子连起来的整条通道)
为什么不用"行/列"而另造一个"轨道"?
因为"行/列"指的是位置 ,而"轨道"强调的是尺寸和空间:
grid-template-rows: 100px 200px→ 第1条轨道高100px,第2条轨道高200px- 你是在定义每条"通道"的宽度/高度,而不是在数第几行
画面感:你站在火车站台上,面前是好几条平行的铁轨(轨道),每条轨道可以跑一列火车(一排子元素)。

五、网格单元格(grid cell)------ 最小的"格子"
画面感 :Excel表格里的一个格子。
一个行轨道和一个列轨道的交集。项目默认占据一个单元格。
列1 列2 列3
行1 [ A ] [ B ] [ C ]
行2 [ D ] [ E ] [ F ]
- A占据的就是第1行第1列这个单元格
- 默认情况下,一个项目只占1个单元格
通俗理解:就像教室的座位表,一个学生默认只坐一个座位。
为什么叫"单元格"(cell)?
从生物学和表格里借来的词
| 领域 | 单元格的意思 |
|---|---|
| Excel | 行和列交叉的那个小方框 |
| 表格 | <td> 叫"table data cell" |
| 生物学 | 细胞是最小单位(cell) |
| 监狱 | 一间间小牢房(cell) |
Grid里的单元格 = 一条行轨道和一条列轨道交叉 出来的最小独立单位
为什么不是"格子"而是"单元格"?
因为"格子"太口语化,而"单元格"强调了它是可以独立存在的最小单元------就像生物体的细胞,不能再拆了。
画面感:你在Excel里看到一个表格,最小的那个小方块就是单元格。一个项目默认就占一个单元格。

六、网格区域(grid area)------ 合并出来的"大块区域"
画面感 :合并多个相邻单元格,形成一个矩形大格子。
由多个单元格组成的矩形区域。可以让一个项目跨越多行多列。
你可以让一个元素:
- 占第1行到第3行
- 占第2列到第4列
这样它就占了一个 3行 × 3列 的大矩形区域。
┌─────┬─────┬─────┐
│ │ │ │
│ 大 │ B │ C │
│ 区 │ │ │
│ 域 ├─────┼─────┤
│ │ D │ E │
└─────┴─────┴─────┘
通俗理解:就像把几个小课桌拼成一个大桌子,几个同学一起用。
为什么叫"区域"(area)?
因为就是字面意思------一块"区域"
当多个单元格合并在一起,就形成了一块连续的矩形区域。
区域 vs 单元格
- 单元格 = 最小单位(1×1)
- 区域 = 多个单元格拼成的大块(比如 2行×3列)
为什么叫"区域"不叫"合并单元格"?
因为"合并单元格"强调的是操作过程 (把几个格子并起来),而"区域"强调的是结果------这块地方现在是一个整体了。
画面感 :你在Excel里选中一片连续的格子,它们形成一个蓝色高亮的矩形区域。你可以给这个区域起个名字叫"header",然后直接把一个元素扔进去。

Grid 完整记忆链条(由小到大 + 为什么这么叫)
| 名词 | 核心比喻 | 一句话理解 | 为什么这么叫 |
|---|---|---|---|
| 网格 | 渔网 + 格子 | 横竖线交织成的网状结构 | 像渔网的"网"+ 格子的"格" |
| 线 | 尺子的刻度 | 划分位置的边界线,可以数编号 | 画表格先画线,线就是边界和编号 |
| 行 | 电影院排 | 横着的一排(左右方向) | 现实世界叫法,"横行" |
| 列 | 竖着的队列 | 竖着的一列(上下方向) | 现实世界叫法,"队列" |
| 轨道 | 火车轨道 / 跑道 | 一整条通道,用来定义尺寸 | 像火车轨道,强调尺寸和空间 |
| 单元格 | Excel格子 / 细胞 | 行与列交叉的最小单位 | 像生物细胞,是最小独立单位 |
| 区域 | 选中的连续矩形 | 多个单元格拼成的大块 | 字面意思,一块连续的"区域" |

6.3 Grid 核心属性(一):容器上的属性
6.3.1 display: grid 与 inline-grid
css
.container {
display: grid; /* 块级网格容器,占满整行宽度 */
}
.container-inline {
display: inline-grid; /* 行内网格容器,宽度由内容撑开 */
}
6.3.2 定义网格结构:grid-template-columns 和 grid-template-rows
你已经知道了:
- 网格线 = 棋盘上的坐标线
- 行 = 横着的一排(横行)
- 列 = 竖着的一排(队列/柱子)
- 轨道 = 一整条通道(火车轨道/跑道)
- 单元格 = 行与列交叉的最小格子
- 区域 = 多个单元格合并成的大块
现在我们要学的是:如何定义网格有多少行、多少列,以及每一行多高、每一列多宽。
这就是 grid-template-columns 和 grid-template-rows 要做的事。
先拆开词本身:grid-template-columns
-
grid------ 网格:就是那张横竖交织的"网+格"。 -
template------ 模板 / 样板为什么叫 template? 想象你盖房子:你先画一张设计图纸 (template),图纸上写着:"第1面墙多厚,第2面墙多厚......"工人按照这张图纸去施工。
template在 Grid 里 = 你提前设定好的"结构蓝图",你告诉浏览器:"按照我这个模板来划分行和列。"画面感 :就像做月饼的模具 ------模具长什么样,月饼就长什么样。
grid-template-columns就是"列方向的模具"。 -
columns------ 列(复数):前面讲过列 = 竖着的一排(像一列火车、一列队伍)。为什么是 column 不是 row?
英文 中文 方向 记忆 column 列 竖 ↕️ 像一根柱子(column 本意就是柱子) row 行 横 ↔️ 像一排划船(row 本意是划船,船桨左右划) -
合起来:
grid-template-columns中文直译 :网格的列方向模板
"我要告诉浏览器,我的网格里每一列有多宽,按什么顺序排列。"
画面感:你拿着一个尺子,在纸上画表格:
- 第1列:200px 宽
- 第2列:1fr(剩下的空间里占1份)
- 第3列:200px 宽
grid-template-columns: 200px 1fr 200px;就是在说这句话。

同理:grid-template-rows
-
rows------ 行(复数)为什么是 row? Row 的本意是"划船"------船桨左右划动,形成横向的排列 。
记忆 :电影院里的 row = 一排座位(横着的) -
合起来:
grid-template-rows中文直译 :网格的行方向模板
"我要告诉浏览器,我的网格里每一行有多高。"
画面感:还是那个表格:
- 第1行:100px 高
- 第2行:auto(内容多高就多高)
- 第3行:100px 高
grid-template-rows: 100px auto 100px;就是在说这句话。

完整代码示例
css
.container {
display: grid;
grid-template-columns: 200px 1fr 200px; /* 三列:固定200px + 自适应 + 固定200px */
grid-template-rows: 100px auto 100px; /* 三行:固定100px + 自适应 + 固定100px */
}
这个网格,列方向 :第一列固定200px,第二列占满剩下的空间,第三列固定200px。
行方向:第一行固定100px高,第二行随内容自动撑高,第三行固定100px高。
视觉画面:
┌─────────┬──────────────────┬─────────┐
│ │ │ │
│ 200px │ 1fr │ 200px │
│ 固定宽 │ (自适应宽) │ 固定宽 │
│ │ │ │
├─────────┼──────────────────┼─────────┤
│ │ │ │
│ auto │ auto │ auto │
│ 内容多高│ 内容多高 │ 内容多高│
│ 就多高 │ 就多高 │ 就多高 │
│ │ │ │
├─────────┼──────────────────┼─────────┤
│ │ │ │
│ 100px │ 100px │ 100px │
│ 固定高 │ 固定高 │ 固定高 │
│ │ │ │
└─────────┴──────────────────┴─────────┘
单位详解(每个都讲透)
1. px ------ 像素(pixel)
| 全称 | 中文 | 是什么 |
|---|---|---|
| pixel | 像素 | 屏幕上的一个发光点 |
为什么叫 pixel?
pix来自 pictures(图片),el来自 element(元素)→ 图片的最小元素
画面感 :你凑近屏幕,看到一个个小光点,每个光点就是一个 px。
在 Grid 里 :200px = 固定占200个小光点的宽度,雷打不动。

2. % ------ 百分比(percent)
| 全称 | 中文 | 是什么 |
|---|---|---|
| percent | 百分比 | per(每)+ cent(百)= 每一百份中的多少 |
画面感 :你把容器宽度切成100份,25% 就是拿其中25份。
注意 :
%是相对于父容器的宽度/高度,不是相对于剩余空间。
示例:
css
.container {
width: 1000px;
grid-template-columns: 25% 75%;
}
/* 第一列 = 250px,第二列 = 750px */

3. fr ------ 分数(fraction)【Grid 最核心的单位】
| 全称 | 中文 | 是什么 |
|---|---|---|
| fraction | 分数 / 部分 | 表示"分一份" |
为什么叫 fr?
fr就是 fraction 的缩写。Fraction 在数学里是"分数",在日常英语里是"一小部分"。
画面感:你和朋友分一个披萨:
- 先拿走固定的几块(
px或%列) - 剩下的披萨,按比例分
css
grid-template-columns: 200px 1fr 2fr;
- 第1列:先拿走200px
- 剩下的空间分成 3份(1+2)
- 第2列占 1份
- 第3列占 2份
为什么 fr 这么重要? 因为以前用
%或px很难做"一个固定,剩下的自适应"。fr就是专门解决这个问题的。

4. auto ------ 自动
| 全称 | 中文 | 是什么 |
|---|---|---|
| auto | 自动 | 由内容决定 |
画面感:你放了一个很长的单词进去,这一列就会变宽到能装下它。你放了一个空 div,这一列就会缩到最小。
autovs1fr的区别:
| 特性 | auto |
1fr |
|---|---|---|
| 如何决定大小 | 由内容决定 | 由剩余空间决定 |
| 会不会被内容撑开 | 会,内容多宽它就多宽 | 会,但会按比例分配 |
| 最小宽度 | 通常是内容的最小宽度(比如一个单词) | 可以被压缩到0(如果内容允许换行) |
示例:
css
grid-template-columns: auto 1fr;
- 第一列:紧贴内容的宽度
- 第二列:占满剩下的所有空间

5. minmax(min, max) ------ 最小最大值
| 全称 | 中文 | 是什么 |
|---|---|---|
| min + max | 最小 + 最大 | 一个范围 |
为什么叫 minmax? 就是 min(最小)和 max(最大)拼在一起。告诉你:"这一列的宽度,在这个范围内变化"。
画面感 :像一个橡皮筋:
- 最窄不能短于
min值 - 最宽不能超过
max值 - 中间可以自由伸缩
示例:
css
grid-template-columns: minmax(100px, 1fr) 2fr;
- 第一列:最小 100px,最大占 1 份剩余空间
- 当容器变窄时,第一列会先被压缩到 100px,然后不再缩小
- 第二列继续被压缩
为什么需要 minmax? 因为
1fr理论上可以被压缩到 0,但如果你不想让某一列太窄(比如侧边栏不能小于 200px),就用minmax(200px, 1fr)。

6. repeat(次数, 值) ------ 重复
| 全称 | 中文 | 是什么 |
|---|---|---|
| repeat | 重复 | 写一次,重复多次 |
为什么叫 repeat? 就是英文"重复"的意思。不想写 1fr 1fr 1fr 1fr 这么长,就写 repeat(4, 1fr)。
画面感:就像复印机------你告诉它"复印4份",它就帮你复制4遍。
示例:
css
/* 这两种写法完全等价 */
grid-template-columns: 1fr 1fr 1fr;
grid-template-columns: repeat(3, 1fr);
/* 复杂一点:重复一个模式 */
grid-template-columns: repeat(2, 100px 1fr);
/* 展开 = 100px 1fr 100px 1fr */

中英文 + 概念速查表
| 英文 | 中文 | 怎么记 |
|---|---|---|
grid |
网格 | 渔网 + 格子 |
template |
模板 / 蓝图 | 做月饼的模具 |
columns |
列 | C 是竖半圆 = 竖,柱子 |
rows |
行 | 电影院一排座位 = 横 |
px |
像素 | 屏幕上的一个光点 |
% |
百分比 | 每100份里拿几份 |
fr |
分数 / 份 | fraction = 分肉,分剩余空间 |
auto |
自动 | 内容多宽/多高就多宽/多高 |
minmax() |
最小最大 | 橡皮筋,有下限有上限 |
repeat() |
重复 | 复印机,复制多份 |
串起所有内容
你要画一张网格 (grid)。
先拿出一张模板 (template)图纸。
在图纸上写:
- 列方向(columns):第一列 200px(固定),第二列 1fr(剩下的分一份),第三列 200px(固定)
- 行方向(rows):第一行 100px,第二行 auto(随内容),第三行 100px
如果有一列你想让它最小 100px,最大 1fr ,就用
minmax(100px, 1fr)。如果你想写 3 个 1fr 又懒得敲三遍,就用
repeat(3, 1fr)。

6.3.3 网格间距:gap
css
.container {
gap: 20px; /* 行间距和列间距都是 20px */
gap: 20px 10px; /* 行间距 20px,列间距 10px */
row-gap: 20px; /* 单独设置行间距 */
column-gap: 10px; /* 单独设置列间距 */
}
注意:gap 不会在网格边缘产生间距,只出现在格子之间。


6.3.4 单元格内对齐:justify-items 和 align-items
-
justify-items:水平方向对齐(每个单元格内)控制单元格内的项目 在水平方向上的对齐方式(相当于 Grid 的
align-items的水平版本)。| 值 | 含义 |
|---|---|---|
|
stretch(默认) | 拉伸填满整个单元格宽度 ||
start| 向单元格左侧对齐 ||
end| 向单元格右侧对齐 ||
center| 单元格内水平居中 |
-
align-items:垂直方向对齐(每个单元格内)控制单元格内的项目在垂直方向上的对齐方式。
| 值 | 含义 |
|---|---|---|
|
stretch(默认) | 拉伸填满整个单元格高度 ||
start| 向单元格顶部对齐 ||
end| 向单元格底部对齐 ||
center| 单元格内垂直居中 |
6.3.5 网格整体对齐:justify-content 和 align-content
-
justify-content:整个网格在容器中的水平对齐当网格的总宽度小于容器宽度时,控制网格整体在容器中的位置。
| 值 | 含义 |
|---|---|---|
|
start(默认) | 网格整体靠左 ||
end| 网格整体靠右 ||
center| 网格整体居中 ||
space-between| 网格两端对齐,列轨道之间间隔相等 ||
space-around| 每个列轨道两侧间隔相等 ||
space-evenly| 列轨道之间及两端间隔全相等 |
-
align-content:整个网格在容器中的垂直对齐当网格的总高度小于容器高度时,控制网格整体在容器中的位置。取值同上。

6.3.6 隐式轨道尺寸:grid-auto-rows 与 grid-auto-columns
当项目被放置到没有明确定义的行或列时,使用这些属性决定隐式轨道的大小。
css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 只定义了 3 列 */
grid-auto-rows: 100px; /* 自动生成的行高度为 100px */
}
如果项目被放到第 4 列(超出定义),grid-auto-columns 会决定那一列的宽度。

6.4 Grid 核心属性(二):项目上的属性
这些属性写在子项目上,控制单个项目在网格中的位置。
1. grid-column 与 grid-row
指定项目从哪条网格线开始,到哪条网格线结束。
css
.item {
grid-column: 1 / 3; /* 从列线1开始,到列线3结束(占2列) */
grid-row: 2 / 4; /* 从行线2开始,到行线4结束(占2行) */
}
简写与等价写法:
| 写法 | 含义 |
|---|---|
grid-column: 1 / 3 |
从第 1 条列线到第 3 条列线 |
grid-column: 1 / span 2 |
从第 1 条列线开始,跨越 2 列 |
grid-column: span 2 / 3 |
跨越 2 列,结束于第 3 条列线 |
grid-column: 2 |
等价于 2 / 3(只占第 2 列) |
组合写法:
css
.item {
grid-column: 1 / span 2; /* 从列线1开始,占2列 */
grid-row: 2 / 4; /* 从行线2开始,到行线4结束 */
}

2. grid-area:两种用法
用法一:通过网格线指定区域
css
.item {
grid-area: 2 / 1 / 4 / 3; /* 行开始 / 列开始 / 行结束 / 列结束 */
}
/* 等价于:grid-row: 2 / 4; grid-column: 1 / 3; */
用法二:通过命名区域
配合容器的 grid-template-areas 使用:
css
.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
这种方法最直观:用 ASCII 画图的方式定义布局。

3. justify-self:覆盖容器的 justify-items
控制单个项目在单元格内的水平对齐,取值同 justify-items。

4. align-self:覆盖容器的 align-items
控制单个项目在单元格内的垂直对齐,取值同 align-items。

6.5 隐式网格 vs 显式网格
这是一个容易混淆但很重要的概念。
显式网格 :你用 grid-template-rows/columns 明确定义的行和列。
隐式网格:当你把项目放到显式网格之外时,浏览器自动创建的行和列。
css
.container {
display: grid;
grid-template-columns: 100px 100px; /* 显式:只定义了2列 */
grid-template-rows: 100px; /* 显式:只定义了1行 */
grid-auto-rows: 50px; /* 隐式行的高度 */
}
html
<div class="container">
<div class="item">1</div> <!-- 放到 (行1, 列1) 显式区域 -->
<div class="item">2</div> <!-- 放到 (行1, 列2) 显式区域 -->
<div class="item">3</div> <!-- 放到 (行2, 列1) → 自动创建第2行,高度50px -->
<div class="item" style="grid-column: 4;">4</div> <!-- 放到第4列 → 自动创建第3、4列 -->
</div>
关键点:
- 隐式轨道的尺寸由
grid-auto-rows和grid-auto-columns控制 - 如果没有设置,默认为
auto(由内容决定) grid-auto-flow控制隐式网格的排列方向(row或column)

6.6 实战案例:从零搭建常见布局
案例一:经典三栏布局(页眉 + 侧边栏 + 主内容 + 页脚)
html
<div class="layout">
<header>页眉</header>
<aside>侧边栏</aside>
<main>主内容区域</main>
<footer>页脚</footer>
</div>
css
.layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
header { grid-area: header; background: #333; color: white; padding: 1rem; }
aside { grid-area: sidebar; background: #f0f0f0; padding: 1rem; }
main { grid-area: main; background: white; padding: 1rem; }
footer { grid-area: footer; background: #333; color: white; padding: 1rem; }
效果 :侧边栏固定 250px,主内容自适应,页脚始终在底部(因为 1fr 把剩余高度分配给 main)。

案例二:图片墙(响应式,自动填充)
html
<div class="gallery">
<img src="1.jpg" alt=""><img src="2.jpg" alt="">
<img src="3.jpg" alt=""><img src="4.jpg" alt="">
<!-- 任意多张图片 -->
</div>
css
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.gallery img {
width: 100%;
height: auto;
aspect-ratio: 1 / 1;
object-fit: cover;
}
auto-fill 与 minmax() 的组合:浏览器自动计算能放下多少列,每列最小 200px,最大占 1 份剩余空间。窗口缩放时,列数自动变化。

案例三:杂志风格卡片布局(不规则网格)
html
<div class="magazine">
<div class="feature">特色文章</div>
<div class="card">卡片1</div>
<div class="card">卡片2</div>
<div class="card">卡片3</div>
<div class="card">卡片4</div>
<div class="card">卡片5</div>
</div>
css
.magazine {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.feature {
grid-column: span 2; /* 特色文章占2列 */
grid-row: span 2; /* 特色文章占2行 */
background: #f8f9fa;
padding: 2rem;
}
.card {
background: white;
border: 1px solid #ddd;
padding: 1rem;
}
效果:第一篇文章是"大卡片"占 2×2 格子,其余卡片正常排列。Grid 会自动调整其他项目的位置来填补空隙。

案例四:仪表盘(复杂区域划分)
html
<div class="dashboard">
<div class="header">仪表盘标题</div>
<div class="sidebar">菜单</div>
<div class="stats">统计图表</div>
<div class="recent">最近活动</div>
<div class="trends">趋势图</div>
<div class="footer">版权信息</div>
</div>
css
.dashboard {
display: grid;
grid-template-areas:
"header header header"
"sidebar stats trends"
"sidebar recent recent"
"footer footer footer";
grid-template-columns: 250px 1fr 1fr;
grid-template-rows: auto 300px auto auto;
gap: 16px;
min-height: 100vh;
}
.header { grid-area: header; background: #2c3e50; color: white; padding: 1rem; }
.sidebar { grid-area: sidebar; background: #34495e; color: white; padding: 1rem; }
.stats { grid-area: stats; background: #ecf0f1; padding: 1rem; }
.recent { grid-area: recent; background: #ecf0f1; padding: 1rem; }
.trends { grid-area: trends; background: #ecf0f1; padding: 1rem; }
.footer { grid-area: footer; background: #2c3e50; color: white; padding: 1rem; }

案例五:响应式网格(移动端一列,平板两列,桌面四列)
css
.grid {
display: grid;
gap: 20px;
grid-template-columns: 1fr; /* 移动端默认:1列 */
}
@media (min-width: 600px) {
.grid {
grid-template-columns: repeat(2, 1fr); /* 平板:2列 */
}
}
@media (min-width: 1000px) {
.grid {
grid-template-columns: repeat(4, 1fr); /* 桌面:4列 */
}
}
或者更简洁地用 auto-fill + minmax() 实现纯响应式:
css
.grid {
display: grid;
gap: 20px;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
/* 浏览器自动根据容器宽度决定列数,无需 media query */
auto-fit 和 auto-fill 的区别:
auto-fill:尽可能多地填充列,即使列是空的也保留轨道auto-fit:填充后,把空轨道的空间分配给非空轨道

6.7 Grid 与 Flex 的配合使用
Grid 和 Flex 不是二选一,而是黄金搭档。
原则:
- 用 Grid 搭建页面的宏观结构(整体框架、大区块)
- 用 Flex 处理微观排列(导航栏内的链接、卡片内的元素)
html
<div class="page">
<header class="header">
<div class="logo">Logo</div>
<nav class="nav"> <!-- 这里用 Flex -->
<a href="#">首页</a>
<a href="#">产品</a>
<a href="#">关于</a>
</nav>
</header>
<main class="main"> <!-- Grid 布局 -->
<aside>侧边栏</aside>
<article>文章</article>
</main>
<footer>页脚</footer>
</div>
css
.page {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header {
display: flex;
justify-content: space-between; /* Flex 处理水平排列 */
align-items: center;
}
.nav {
display: flex;
gap: 20px; /* Flex 处理链接间距 */
}
.main {
display: grid;
grid-template-columns: 250px 1fr;
}
经验法则:父容器定大局用 Grid,子元素内部排小队用 Flex。

6.8 Grid vs Flex:何时用哪个?
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 导航栏(一排链接) | Flex | 一维排列,简单直接 |
| 整体页面框架(页眉/侧边栏/主内容/页脚) | Grid | 二维结构,行列对齐 |
| 卡片列表(自动换行) | 两者皆可 | Flex-wrap 或 Grid auto-fill |
| 图片墙(多行多列,行列对齐) | Grid | 天然网格,行列可控 |
| 表单内的标签+输入框 | Flex | 简单行内对齐 |
| 仪表盘、杂志布局 | Grid | 复杂区域跨行跨列 |
| 垂直居中 | 两者皆可 | Flex 更简洁 |
| 等分布局(无跨行跨列需求) | 两者皆可 | Flex:1 或 Grid:1fr |
一个简单的判断流程:
- 问自己:这个布局是一维 (只有行或只有列)还是二维(行和列都要控制)?
- 如果是一维 → 用 Flex
- 如果是二维 → 用 Grid
- 如果不确定 → 先试 Grid,因为 Grid 可以做任何 Flex 能做的事(只是代码可能略长)

本章小结
- Grid 容器 = 二维网格系统
- 核心概念:网格线、网格轨道、网格单元格、网格区域
- 关键单位 :
fr(剩余空间分数)、minmax()、repeat() - 显式网格 :用
grid-template-*定义 - 隐式网格 :自动生成,用
grid-auto-*控制 - 项目定位 :
grid-column、grid-row、grid-area(支持命名区域) - Grid 与 Flex 是互补关系:Grid 管大局,Flex 管细节