CSS Grid 和 Flex 有什么区别?什么时候用 Grid?
简化版
Flex 是一维布局,主要处理一行或一列;Grid 是二维布局,可以同时控制行和列。页面整体网格、卡片矩阵、复杂区域排版更适合 Grid,组件内部线性排列更适合 Flex。
详细版
Grid 的核心概念包括:
- Grid Container:设置
display: grid的容器。 - Grid Item:容器的直接子元素。
- 行和列:通过
grid-template-columns、grid-template-rows定义。 - 网格线和区域:可以用线号或
grid-template-areas放置元素。 - 间距:用
gap设置。
典型写法:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
这段代码能实现响应式卡片网格:容器宽时多列,窄时自动减少列数。面试回答时可以说:Flex 更像“排队”,Grid 更像“铺棋盘”。
完整版教学
一、Flex 和 Grid 的核心差异
Flex 的思路是先选一条主轴,然后把子项沿主轴排列。它也能换行,但换行后的每一行更像独立的 flex line,行与行之间不是一个完整二维系统。
Grid 的思路是先定义一个网格,再把元素放到网格里。它天然知道行和列,所以更适合整体布局。
二、Grid 的常见工程场景
响应式卡片列表是 Grid 的经典场景:
.list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
minmax(220px, 1fr) 表示每列最小 220px,最大平分剩余空间;auto-fit 表示能放几列就放几列。这样不需要写一堆媒体查询。
页面框架也适合 Grid:
.page {
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
gap: 24px;
}
左侧固定导航,右侧自适应内容,非常清楚。
三、Grid areas 提升可读性
复杂页面可以用区域命名:
.layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 220px 1fr;
}
这种写法可读性很好,一眼能看出页面结构。缺点是动态布局特别复杂时,维护 areas 可能变麻烦。
四、选择标准
判断标准很简单:如果布局重点是一条轴上的对齐和伸缩,用 Flex;如果重点是行列关系、二维分区或响应式网格,用 Grid。
实际工程里两者常常配合使用:页面大结构用 Grid,卡片内部、按钮组、导航菜单用 Flex。这不是二选一,而是分工。
五、面试追问与工程落地
Grid 常见追问是 auto-fit 和 auto-fill 的区别。两者都会尽量创建可容纳的列,但当有空轨道时,auto-fit 会折叠空轨道,让已有列拉伸占满空间;auto-fill 会保留空轨道位置。卡片自适应列表里通常更常用 auto-fit。
另一个工程重点是 minmax(0, 1fr)。在 Grid 或 Flex 中,内容默认最小尺寸可能撑开轨道,导致 1fr 看起来“不听话”。使用 minmax(0, 1fr) 可以明确允许轨道缩小到 0,避免长文本或表格把布局撑爆。
Grid 也不意味着完全不需要媒体查询。对于简单卡片矩阵,repeat(auto-fit, minmax()) 很强;但对于页面信息架构变化,比如移动端侧栏变顶部、左右布局变上下布局,媒体查询仍然是清晰的断点表达。
六、用容器宽度推导自动列数
设容器宽 800px,列间距 20px,轨道写成 repeat(auto-fit, minmax(240px, 1fr))。放 3 列至少需要 3 × 240 + 2 × 20 = 760px,能容纳;放 4 列至少需要 4 × 240 + 3 × 20 = 1020px,因此本例最多 3 列。扣除 gap 后的 760px 轨道空间再由三个 1fr 分配,每列约 253.33px。
| 概念 | Grid | Flex |
|---|---|---|
| 主要建模 | 行列二维轨道 | 单条主轴及多条独立 flex line |
| 空间入口 | 先定义轨道,再放项目 | 先取项目基础尺寸,再分剩余空间 |
| 典型自适应 | auto-fit + minmax() | flex-wrap + flex-basis |
| 视觉重排风险 | 显式放置或 dense 可能改视觉顺序 | order、反向轴可能改视觉顺序 |
auto-fill 与 auto-fit 在计算能容纳多少重复轨道时相近,差异出现在放置项目后:auto-fit 会折叠空的重复轨道,已有列因而能拉伸;auto-fill 保留空轨道。选择它们取决于空位是否应该继续占据网格结构,而不是固定背某一个“更好”。
1fr写在轨道外部时隐含自动最小值,长内容可能把轨道撑开;需要明确允许收缩的主内容列时,minmax(0, 1fr)通常比裸1fr更稳。
七、常见误区与追问
- 误区:用了 Grid 就绝对不需要媒体查询。 自动轨道能处理尺寸伸缩,但信息架构从侧栏变顶部等模式切换仍适合用断点表达。
- 误区:Flex 能换行,所以它与 Grid 都是同一种二维布局。 Flex 每条线独立分配主轴空间,Grid 的项目共享统一的行列轨道。
- 误区:
1fr永远等于容器宽度的一个平均份额。 它分的是扣除固定轨道、gap 等后的可分配空间,还会受轨道自动最小尺寸和内容贡献影响。 - 追问:
auto-fit与auto-fill的核心区别是什么? 项目放置后,前者折叠空重复轨道,后者保留空轨道位置。 - 追问:为什么
minmax(0, 1fr)能缓解长文本溢出? 它把轨道最小值明确设为零,不再让隐含的 auto 最小值优先保留内容最小宽度。 - 追问:
grid-auto-flow: dense有什么代价? 它会回填较早的空洞,视觉顺序可能与 DOM 顺序不同,必须评估阅读和键盘导航体验。 - 追问:页面布局能否外层 Grid、组件内部 Flex? 可以,两者解决的层次不同,这种组合正是常见工程用法。
八、加强记忆
Flex 像“队伍”,关心队伍方向、间距、对齐;Grid 像“棋盘”,先画行列,再把元素放进格子。遇到二维布局优先想 Grid,遇到单行单列对齐优先想 Flex。