CSS Grid 布局完全指南
一、什么是 Grid
Grid(网格布局)是 CSS 的二维布局系统,可以同时控制行和列。与 Flexbox(一维,只控制行或列中的一个方向)不同,Grid 让你在预定义的网格上精确放置元素。
一句话理解:把容器想象成一张表格,你可以随意定义行、列的数量和大小,然后让子元素占据任意单元格。
二、核心概念
网格线(Grid Line)
定义网格的分界线,从 1 开始编号。
1 2 3 4
| col1 | col2 | col3 |
1 +------+------+------+
| | | |
| row1 | | |
2 +------+------+------+
| | | |
| row2 | | |
3 +------+------+------+
- 竖线是列线(column line),共 4 条
- 横线是行线(row line),共 3 条
- 可以用负数从末尾反向编号:
-1表示最后一条线
网格轨道(Grid Track)
两条相邻网格线之间的空间,即一行或一列。
网格单元格(Grid Cell)
四条网格线围成的最小单位。
网格区域(Grid Area)
一个或多个单元格组成的矩形区域。
三、激活 Grid
.container {
display: grid; /* 块级网格 */
/* 或 */
display: inline-grid; /* 行内网格 */
}
激活后,直接子元素自动成为网格项目(grid item)。
四、容器属性
以下所有属性都设置在父容器(.container)上。
4.1 定义行和列
grid-template-columns
定义列的宽度和数量。
.container {
/* 固定宽度:3 列 */
grid-template-columns: 200px 1fr 200px;
/* 等宽 3 列 */
grid-template-columns: 1fr 1fr 1fr;
grid-template-columns: repeat(3, 1fr); /* 等价写法 */
/* 不等宽 */
grid-template-columns: repeat(3, 1fr) repeat(2, 2fr);
/* 结果: 1fr 1fr 1fr 2fr 2fr */
/* 最小-最大范围 */
grid-template-columns: repeat(3, minmax(100px, 1fr));
/* 混合单位 */
grid-template-columns: 200px 1fr auto;
}
grid-template-rows
定义行的高度和数量。
.container {
grid-template-rows: 60px 1fr 40px; /* 顶栏 60px,中间自适应,底栏 40px */
grid-template-rows: repeat(4, 100px); /* 4 行,每行 100px */
grid-template-rows: auto 1fr auto; /* 内容撑开 */
}
4.2 fr 单位
fr(fraction)代表剩余自由空间的份额。
grid-template-columns: 1fr 2fr 1fr;
/* 总空间分成 1+2+1=4 份,第二列占 2/4 */
注意:fr 分配的是剩余空间,如果有固定宽度的列,会先扣除。
grid-template-columns: 200px 1fr 1fr;
/* 先扣除 200px,剩余空间平分给两个 1fr */
4.3 常用函数
| 函数 | 说明 | 示例 |
|---|---|---|
repeat(n, value) | 重复模式 | repeat(3, 1fr) |
minmax(min, max) | 最小-最大值范围 | minmax(100px, 1fr) |
min(a, b) | 取两者较小值 | min(50%, 300px) |
max(a, b) | 取两者较大值 | max(200px, 20vw) |
fit-content(limit) | 内容自适应,不超过 limit | fit-content(300px) |
clamp(min, ideal, max) | 理想值在范围内自适应 | clamp(200px, 50%, 600px) |
4.4 自动填充 — 响应式利器
.container {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
原理:每列至少 200px,在容器宽度内尽可能多地创建列,剩余空间平均分配(1fr)。
auto-fill vs auto-fit
auto-fill(容器 900px,每列 min 200px):
┌──────┬──────┬──────┬──────┐ ← 创建 4 列,第 4 列是空的但保留空间
│ 1 │ 2 │ 3 │ │
└──────┴──────┴──────┴──────┘
auto-fit:
┌──────┬──────┬──────┐ ← 只创建 3 列(因为只需要 3 列装内容)
│ 1 │ 2 │ 3 │ ← 空列折叠,现有列扩展填满
└──────┴──────┴──────┘
经验法则:大多数情况下用 auto-fit,效果更符合直觉。
4.5 命名区域 — grid-template-areas
用可视化的方式定义布局。
.container {
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: 60px 1fr 40px;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
规则:
- 每行用一对引号包裹,列之间用空格分隔
- 每行的列数必须相同
- 用
.表示空白区域
grid-template-areas:
"header header"
". main" /* 左侧留空 */
"footer footer";
4.6 间距 — gap
.container {
gap: 20px; /* 行间距和列间距都是 20px */
gap: 20px 10px; /* 行间距 20px,列间距 10px */
row-gap: 20px; /* 仅行间距 */
column-gap: 10px; /* 仅列间距 */
}
gap 只作用于网格内部,不影响容器边缘。
4.7 自动放置 — grid-auto-flow
当项目没有明确指定位置时,如何自动排列。
.container {
grid-auto-flow: row; /* 默认,从左到右逐行填充 */
grid-auto-flow: column; /* 从上到下逐列填充 */
grid-auto-flow: dense; /* 紧密填充,填补前面的空隙 */
}
4.8 自动轨道大小
当项目超出定义的网格时,自动创建的轨道大小。
.container {
grid-template-columns: 100px 100px; /* 只定义了 2 列 */
grid-auto-columns: 1fr; /* 第 3 列及以后宽度为 1fr */
grid-auto-rows: 80px; /* 新增行高 80px */
}
4.9 单元格内对齐(影响所有项目)
justify-items — 水平对齐
.container {
justify-items: start; /* 靠左 */
justify-items: end; /* 靠右 */
justify-items: center; /* 居中 */
justify-items: stretch; /* 拉伸填满(默认) */
}
align-items — 垂直对齐
.container {
align-items: start; /* 靠上 */
align-items: end; /* 靠下 */
align-items: center; /* 居中 */
align-items: stretch; /* 拉伸填满(默认) */
}
place-items — 简写
.container {
place-items: center; /* 水平垂直都居中 */
place-items: center stretch; /* 垂直居中,水平拉伸 */
}
4.10 整个网格在容器中的对齐
当网格总大小小于容器大小时生效。
.container {
justify-content: center; /* 水平居中 */
justify-content: space-between; /* 列之间均匀分布 */
align-content: center; /* 垂直居中 */
align-content: space-around; /* 行之间均匀分布 */
}
五、项目属性
以下属性设置在网格的直接子元素(item)上。
5.1 指定位置 — grid-column / grid-row
.item {
/* 从第 1 条列线到第 3 条列线 */
grid-column-start: 1;
grid-column-end: 3;
/* 简写 */
grid-column: 1 / 3;
/* 跨越 2 行 */
grid-row: 1 / span 2;
/* 从结尾倒数第 1 条线到倒数第 3 条线 */
grid-column: -1 / -3;
/* 横跨所有列 */
grid-column: 1 / -1;
}
grid-column: 2 / 4 的效果:
1 2 3 4
| |██████|██████| ← 从线 2 到线 4
| |██████|██████|
5.2 命名区域 — grid-area
.item {
grid-area: header; /* 引用 grid-template-areas 中的名称 */
grid-area: 1 / 1 / 3 / 3; /* row-start / col-start / row-end / col-end */
}
5.3 单个项目对齐
覆盖容器的 justify-items / align-items 设置。
.item {
justify-self: center; /* 水平居中 */
align-self: end; /* 垂直靠下 */
/* 简写 */
place-self: center end; /* 垂直居中,水平靠右 */
}
六、网格线编号规则
1 2 3 4 ← 正数
| col1 | col2 | col3 |
-4 -3 -2 -1 ← 负数
- 编号从
1开始,不是从 0 - 负数从末尾倒数:
-1是最后一条线 - 可以给网格线命名:
grid-template-columns: [sidebar-start] 200px [sidebar-end main-start] 1fr [main-end];
七、min-content / max-content
grid-template-columns: min-content 1fr max-content;
| 值 | 含义 |
|---|---|
min-content | 内容所需最小空间(如一个单词的宽度) |
max-content | 内容所需最大空间(如不换行的完整文本宽度) |
auto | 默认,根据内容自动计算 |
八、常见布局模式
8.1 响应式卡片网格
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
一行 CSS 实现响应式卡片,无需任何 @media 查询。
8.2 经典页面布局
.page {
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;
}
8.3 不规则画廊
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
gap: 10px;
}
.wide { grid-column: span 2; } /* 宽 2 格 */
.tall { grid-row: span 2; } /* 高 2 格 */
.featured { grid-column: span 2; grid-row: span 2; } /* 2×2 大方块 */
8.4 完美居中
.center {
display: grid;
place-items: center;
height: 100vh;
}
8.5 固定侧边栏 + 自适应主内容
.app {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr;
height: 100vh;
}
.app > header { grid-column: 1 / -1; } /* header 横跨所有列 */
8.6 Holy Grail Layout(圣杯布局)
.holy-grail {
display: grid;
grid-template-columns: 150px 1fr 150px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 10px;
}
.holy-grail > header { grid-column: 1 / -1; grid-row: 1; }
.holy-grail > nav { grid-column: 1; grid-row: 2; }
.holy-grail > main { grid-column: 2; grid-row: 2; }
.holy-grail > aside { grid-column: 3; grid-row: 2; }
.holy-grail > footer { grid-column: 1 / -1; grid-row: 3; }
九、Grid vs Flexbox
| Grid | Flexbox | |
|---|---|---|
| 维度 | 二维(行 + 列) | 一维(行 或 列) |
| 先定义布局还是内容 | 先定义网格(容器驱动) | 内容决定大小(内容驱动) |
| 适用场景 | 页面框架、卡片网格、复杂布局 | 导航栏、按钮组、列表、单行/列 |
| 重叠元素 | 支持(通过相同区域) | 不支持 |
| 学习曲线 | 较陡 | 较平缓 |
最佳实践:外层用 Grid 做整体框架,内部组件用 Flexbox 做细节布局。两者配合使用。
十、实用技巧
隐式网格线
即使没有显式定义第 5 条线,你也可以使用它:
grid-template-columns: 1fr 1fr 1fr; /* 定义了 4 条线 */
.item { grid-column: 1 / 5; } /* 可以使用 5,会自动扩展 */
span 关键字
grid-column: span 2; /* 从当前位置向右跨 2 列 */
grid-column: span 2 / 4; /* 到第 4 条线结束,向左跨 2 列 */
dense 填充算法
grid-auto-flow: row dense;
让后面的小项目填补前面留下的空隙(可能造成视觉顺序混乱,适合数据看板)。
层叠(Overlap)
多个项目可以占据相同的网格区域,实现层叠效果:
.image { grid-area: 1 / 1 / 3 / 3; }
.caption { grid-area: 2 / 2 / 3 / 3; z-index: 1; }