Css 之Grid布局
1. Grid 到底解决什么问题
在网页里,布局工具大致有三类思路:
- 普通文档流:元素从上往下排
- Flex:一维布局,主要处理“一行”或者“一列”
- Grid:二维布局,同时处理“多行 + 多列” ([MDN Web Docs][1])
所以一句话记住:
Flex 适合排一条线,Grid 适合排一张网。
例如:
- 导航栏一排按钮:Flex 更顺手
- 整个页面分头部、侧边栏、主内容、底部:Grid 更合适
- 商品卡片九宫格:Grid 更合适
- 仪表盘模块布局:Grid 更合适
2. Grid 的核心思维
Grid 的本质就两步:
- 先把父元素定义成网格容器
- 再定义列、行,以及子元素怎么摆进去
最基础的写法:
1 | .container { |
只要写了这个,.container 就成了 grid container,它的直接子元素就变成 grid items。Grid 是通过 display: grid 启用的。
3. 最小可运行示例
先看最简单的例子:
1 | <div class="container"> |
1 | .container { |
这段代码的意思:
display: grid:启用 Gridgrid-template-columns: 100px 100px:定义两列,每列 100pxgrid-template-rows: 80px 80px:定义两行,每行 80pxgap: 10px:格子之间间距 10px
结果就是一个 2 列 2 行 的网格。
4. 先学最重要的 4 个属性
4.1 display: grid
开启 Grid。
1 | .container { |
4.2 grid-template-columns
定义列。
1 | .container { |
表示 3 列,每列 200px。grid-template-columns 就是定义列轨道尺寸。
也可以这样写:
1 | grid-template-columns: 1fr 1fr 1fr; |
这里的 fr 是 Grid 里最常用的单位之一,表示 按比例分剩余空间。
比如:
1 | grid-template-columns: 1fr 2fr 1fr; |
意思是:
- 第一列占 1 份
- 第二列占 2 份
- 第三列占 1 份
总共 4 份,所以中间那列最宽。
4.3 grid-template-rows
定义行。
1 | grid-template-rows: 100px 200px; |
表示两行:
- 第一行 100px
- 第二行 200px
4.4 gap
定义网格间距。
1 | gap: 16px; |
等价于:
1 | row-gap: 16px; |
如果想分别控制:
1 | row-gap: 20px; |
5. fr 是 Grid 里最关键的单位
初学 Grid,最容易卡的就是 fr。
可以把它理解为:
剩余空间分配单位
看例子:
1 | .container { |
含义:
- 第一列固定 200px
- 后面两列平分剩余空间
再看:
1 | grid-template-columns: 1fr 2fr 1fr; |
含义:
- 总份数 = 1 + 2 + 1 = 4
- 第二列拿 2/4,也就是一半
- 两边各拿 1/4
实际开发里,fr 用得非常多,因为它天然适合响应式布局。MDN 的 Grid 教程也把它作为基础能力来介绍。
6. repeat():别重复手写
比如你想写 4 列,每列都一样宽:
1 | grid-template-columns: 1fr 1fr 1fr 1fr; |
可以简写成:
1 | grid-template-columns: repeat(4, 1fr); |
再比如:
1 | grid-template-columns: repeat(3, 200px); |
表示 3 列,每列 200px。
这是最常见写法之一。
7. Grid 里的“线”概念
Grid 不只是“格子”,更准确说是由很多 线 划出来的。
例如:
1 | grid-template-columns: repeat(3, 1fr); |
3 列其实会有 4 条竖线:
- 第 1 条线:最左边
- 第 2 条线:第 1 列和第 2 列之间
- 第 3 条线:第 2 列和第 3 列之间
- 第 4 条线:最右边
行也是同理。
这个概念很重要,因为很多定位其实不是“放到第几个格子”,而是:
从第几条线开始,到第几条线结束。
8. 子元素怎么指定位置
假设有这样一个容器:
1 | .container { |
子元素可以这样指定:
1 | .item1 { |
意思是:
- 从第 1 条列线开始,到第 3 条列线结束
- 所以横向占 2 列
- 从第 1 条行线开始,到第 2 条行线结束
- 所以纵向占 1 行
简化理解:
1 | grid-column: start / end; |
比如:
1 | .item2 { |
表示从第 2 条列线到第 4 条列线,也就是占第 2、3 两列。
9. span:更符合直觉
有时候你不想写“到第几条线结束”,你只想说“占几列”。
这时用 span:
1 | .item { |
表示:
这个元素横向占 2 列。
再比如:
1 | .item { |
表示纵向占 3 行。
10. 自动摆放机制
如果你不给子元素写位置,Grid 会自动排。
比如:
1 | .container { |
里面放 7 个元素,浏览器会自动这样排:
- 第一行 3 个
- 第二行 3 个
- 第三行 1 个
这叫 auto-placement,也就是自动布局。MDN 也专门把它列为 Grid 的核心概念。(place 放置 /pleɪs/ ; ment 状态,结果 /mənt/)
如果你给某些元素指定了跨列、跨行,自动摆放会继续补空位。
11. justify-items、align-items、place-items
这组属性是控制 格子里的内容怎么对齐。
假设每个格子都比内容大,就需要决定内容放哪里。
11.1 水平方向
1 | justify-items: start; |
11.2 垂直方向
1 | align-items: start; |
11.3 合并写法
1 | place-items: center; |
等价于:
1 | justify-items: center; |
12. justify-content、align-content 跟上面不是一回事
justify-items / align-items:控制 单元格内部内容justify-content / align-content:控制 整个网格在容器里的位置
当整个网格没有撑满容器时,justify-content 和 align-content 才明显。
例如:
1 | .container { |
这里网格本身只有 300×200,所以会整体在容器中居中。
13. 页面布局实战:头部 + 侧边栏 + 主内容 + 底部
这是 Grid 最经典的应用。
HTML
1 | <div class="layout"> |
CSS
1 | .layout { |
这个布局的意思:
- 两列:左侧固定 240px,右侧自适应
- 三行:头部 60px,中间撑满,底部 50px
- 头部和底部都横跨两列
这是最基础的后台布局写法。
14. grid-template-areas:可读性更强
如果你不想写一堆 grid-column,可以用区域命名。
1 | .layout { |
这个写法的优点是:
- 一眼就能看出页面结构
- 维护成本低
- 很适合复杂页面骨架
grid-template/grid-template-areas 也是 Grid 模板定义的重要部分。
15. 响应式怎么做
Grid 很适合响应式,但别指望一套代码打天下。
最常见做法:
方法 1:auto-fit + minmax
1 | .list { |
适合卡片流。
方法 2:媒体查询切列数
1 | .layout { |
小屏时把双栏改成单栏。
方法 3:配合 grid-template-areas
1 | .layout { |
这个对于复杂页面很实用。
17. Grid 常见坑
17.1 忘了父元素必须是 display: grid
你给子元素写:
1 | grid-column: 1 / 3; |
但父元素不是 grid container,完全没用。
17.2 只对直接子元素生效
Grid 只管 父元素的直接子元素。
1 | <div class="container"> |
这里 .item 不是 .container 的直接子元素,所以 .container 的 Grid 不会直接摆 .item。
17.3 行高没定义时,表现和你想的不一样
如果你只定义列,不定义行:
1 | grid-template-columns: repeat(3, 1fr); |
那行高通常会由内容撑开。
这不是错,是正常行为。
如果你想统一行高,要写:
1 | grid-auto-rows: 120px; |
或者:
1 | grid-template-rows: repeat(2, 120px); |
17.4 1fr 不是“永远平均”
它是“分配剩余空间”,不是“绝对平均”。
如果你前面有固定列:
1 | grid-template-columns: 200px 1fr 1fr; |
那是先扣掉 200px,再把剩余空间平分。
17.5 内容过长会把布局挤坏
有时某个单元格里是长字符串、长代码、超长链接,会把列撑爆。
常见处理:
1 | .item { |
这个在实际项目里很常见。
18. auto-fill 和 auto-fit 的区别
auto-fill / auto-fit 只能用在 repeat() 里 它们本质不是“值”,而是:一种“列数量生成策略”
1 | grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); |
两者都能自动生成列。
区别在于:
auto-fill:尽量“保留空轨道”auto-fit:会让实际有内容的列尽量撑开
18.1 核心差异
fill:先算列数 → 所有列都参与分配(包括空列)
fit:先算列数 → 空列删除 → 剩下的列参与分配
你可以这样理解(更准确):
- auto-fill
1 | 1. 计算最多能放多少列 |
- auto-fit
1 | 1. 计算最多能放多少列 |
fill:先分列数,然后所有列(包括空列)均分空间
fit:先分列数,去掉空列,然后剩下的列均分空间
fill:空列也参与分配
fit:空列不参与分配
18.2 很关键的点
👉 “均分”只有在 max 是 1fr 时才成立
如果是:
1 | minmax(200px, 300px) |
那就不是“均分”了,而是:
最多分到 300px,然后停住
18.3 工程翻译 辅助记忆
auto-fill
自动填满轨道(哪怕是空的)
👉 关键词:
“填满 + 保留空位”auto-fit
自动贴合内容(删除空轨道)
👉 关键词:
“贴合 + 去空位”auto-fill
先画满格子 → 再往里放元素
👉 格子是主角
👉 元素只是填进去auto-fit
先画格子 → 把空格子删掉 → 剩下的拉伸
👉 元素是主角
👉 格子为元素服务
19. minmax() 很重要
minmax(min, max) 表示轨道尺寸最小值和最大值。
例如:
1 | grid-template-columns: repeat(3, minmax(150px, 1fr)); |
意思是:
- 每列最小 150px
- 最大可拉伸到 1fr
这能避免列太窄,也能保证大屏下能扩展。
20. subgrid 是什么
subgrid 用在嵌套网格里。它允许子网格继承父网格的行或列轨道。这个能力已广泛可用。 ([MDN Web Docs][8])
简单理解:
你有一个大 Grid,里面每个卡片又是个 Grid。如果你想让内部布局和外部列线严格对齐,subgrid 很有用。

