在 CSS 布局的演进史中,曾经历了"table 时代"→"float 时代"→"position 时代"的三次蜕变。每一次蜕变都解决了上一代的痛点,却也带来新的理解成本。
Flexbox 和 Grid 的出现,才是真正意义上"为布局而生"的方案——它们不是技巧,而是一套完整的布局模型。
然而,现实中大量工程师对两者的使用仍停留在"会用不精"的阶段:
display: flex配合justify-content: center走天下,grid-template-columns只会repeat(3, 1fr)。本文的目标:让你真正理解 Flex 和 Grid 的底层模型,掌握何时用哪个、为什么这样用。
目录
一、先把思维模型建对
1.1 Flex:一维流,解决"排列问题" 1.2 Grid:二维网格,解决"区域划分问题"
1.3 黄金选择法则
二、Flexbox 进阶:你可能没真正理解的部分
2.1 flex 三值的真正含义 2.2 flex-shrink 的收缩计算
2.3 常被忽视的对齐轴 2.4 一个经典实战:顶满剩余空间的侧边栏
三、CSS Grid 进阶:真正用好它
3.1 理解"网格线"是核心 3.2 fr 单位:弹性比例分配
3.3 命名区域:让布局结构一目了然 3.4 auto-fit vs auto-fill 的区别
3.5 Grid 中的隐式网格
四、Flex vs Grid 的深层差异
五、工程实践建议
5.1 不要害怕嵌套 5.2 用 gap 替代 margin
5.3 调试技巧:善用浏览器 DevTools
一、先把思维模型建对
1.1 Flex:一维流,解决"排列问题"
Flexbox 的核心是一条轴线。容器沿主轴(main axis)排列子项,沿交叉轴(cross axis)对齐它们。
思维模型:你是一个工厂流水线,子项依次从一端送入,你控制:
- 子项之间的间距(
justify-content) - 每个子项横向的膨胀/收缩比例(
flex-grow/flex-shrink) - 换行策略(
flex-wrap)
Flex 擅长解决的问题:
- 一组元素横向/纵向排列
- 某个子项占满剩余空间
- 子项垂直居中
1.2 Grid:二维网格,解决"区域划分问题"
Grid 是真正的二维布局。你先定义"画布上的网格线",再把元素放进格子里。
思维模型:你是一个版式设计师,先画出行列框架,再往格子里填内容。
Grid 擅长解决的问题:
- 整页/区块的宏观布局(侧边栏 + 主内容 + 页眉页脚)
- 卡片瀑布流、等分网格
- 元素跨行/跨列放置
1.3 黄金选择法则
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 导航栏、工具栏 | Flex | 一维排列,弹性伸缩 |
| 表单字段组 | Flex | 标签 + 输入框对齐 |
| 整体页面骨架 | Grid | 二维区域划分 |
| 卡片列表 | Grid | 等分且自适应 |
| 复杂卡片内部 | Flex | 内容排列、间距控制 |
| 全屏轮播 | Grid / Flex 均可 | 视具体结构选择 |
💡记住:Flex 和 Grid 不是互斥的,真实项目里大量场景是Grid 做外层框架 + Flex 做内部排列。
二、Flexbox 进阶:你可能没真正理解的部分
2.1flex三值的真正含义
大多数人只记得flex: 1,却不知道它等于flex: 1 1 0,这三个值分别是:
flex-grow:剩余空间的占比分配flex-shrink:空间不足时的收缩比flex-basis:主轴上的初始尺寸(优先级高于width)
flex-basis: 0vsflex-basis: auto的区别是关键:
css
复制
/* 两个子项,内容分别是"短"和"这是一段很长的文字" */ /* 方案A:flex: 1 → flex: 1 1 0 */ .item { flex: 1; } /* 两项完全等宽,不管内容多少 */ /* 方案B:flex: 1 1 auto */ .item { flex: 1 1 auto; } /* 先按内容撑开,再等比分配剩余空间,内容长的更宽 */选哪个?做等宽分栏用flex: 1;做内容自适应分栏用flex: 1 1 auto。
2.2flex-shrink的收缩计算
容器 600px,子项 A(300px,shrink=2)+ 子项 B(300px,shrink=1),总宽超出 100px:
收缩权重 = shrink × flex-basis A权重 = 2 × 300 = 600 B权重 = 1 × 300 = 300 总权重 = 900 A收缩 = 100 × 600/900 ≈ 67px → 最终 233px B收缩 = 100 × 300/900 ≈ 33px → 最终 267px这就是为什么你设置了flex-shrink: 0就能防止某个子项被压缩(比如 logo 图片)。
2.3 常被忽视的对齐轴
很多人混淆align-items和align-content:
align-items:控制单行内子项在交叉轴上的对齐align-content:控制多行之间的间距(仅在flex-wrap: wrap且有多行时生效)
典型陷阱:多行 Flex 布局,设了align-items: center却没居中——原因是align-content默认为stretch,每行高度已被撑满,align-items在已满的行内居中,视觉上无效果。
2.4 一个经典实战:顶满剩余空间的侧边栏
css
复制
.layout { display: flex; min-height: 100vh; } .sidebar { width: 240px; flex-shrink: 0; /* 不被压缩 */ } .main { flex: 1; /* 占满剩余宽度 */ overflow: auto; }关键点:flex-shrink: 0保护 sidebar 不变形,flex: 1让 main 自动填满,两行代码胜过任何float+clearfix方案。
三、CSS Grid 进阶:真正用好它
3.1 理解"网格线"是核心
Grid 的一切都建立在"线"上,而不是"格子"。一个 3 列的网格有4 条列线(编号 14,或从右往左 -1-4)。
css
复制
.grid { display: grid; grid-template-columns: 200px 1fr 2fr; /* 列线1 列线2 列线3 列线4 */ } /* 子项从第1条线跨到第3条线(占前两列)*/ .item-wide { grid-column: 1 / 3; } /* 用负数从末尾计数:跨到最后一条线 */ .item-full { grid-column: 1 / -1; }掌握线的概念,才能真正控制元素位置。
3.2fr单位:弹性比例分配
fr(fraction)是 Grid 专有单位,代表"剩余空间的份额":
css
复制
/* 三列:固定 200px + 剩余空间的1/3 + 剩余空间的2/3 */ grid-template-columns: 200px 1fr 2fr; /* 等分三列(最常用)*/ grid-template-columns: repeat(3, 1fr); /* 自适应列数:每列最小 200px,最大 1fr */ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));最后一行是响应式卡片布局的利器——无需媒体查询,浏览器宽了自动多列,窄了自动少列。
3.3 命名区域:让布局结构一目了然
css
复制
.page { display: grid; grid-template-areas: "header header" "sidebar main" "footer footer"; grid-template-columns: 240px 1fr; grid-template-rows: 60px 1fr 50px; min-height: 100vh; } .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } .footer { grid-area: footer; }这是 Grid 最强的能力之一:布局结构写在 CSS 里,HTML 不需要嵌套层级。视觉和代码结构高度吻合,维护成本极低。
3.4auto-fitvsauto-fill的区别
这是面试高频题,也是真实项目的痛点:
auto-fill:即使列容不下内容,也会保留空白列占位auto-fit:多余的空列会"折叠"成 0 宽度,现有列填满容器
css
复制
/* 只有2个卡片时 */ /* auto-fill: 生成多个空列,2个卡片靠左,右边留白 */ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* auto-fit: 空列折叠,2个卡片各占1fr,平分容器 */ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));结论:卡片列表用auto-fit,需要固定列数占位用auto-fill。
3.5 Grid 中的隐式网格
只定义了 3 列,但子项有 10 个——超出部分进入隐式网格,行高由grid-auto-rows控制:
css
复制
.grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 200px; /* 隐式行高固定 200px */ /* 或者 */ grid-auto-rows: minmax(100px, auto); /* 最小100px,内容多时自动撑高 */ }不设置grid-auto-rows的话,行高由内容决定,可能出现高度参差不齐的情况。
四、Flex vs Grid 的深层差异
一句话总结两者的本质区别:
Flex 是内容驱动的(子项决定空间分配);
Grid 是容器驱动的(容器决定格子大小,子项填进去)。
这个区别影响的是你写代码时的思考起点:
- 用 Flex:先想"我有几个子项,它们怎么排列"
- 用 Grid:先想"整体空间怎么划分,然后往里填内容"
实际上,很多布局既能用 Flex 也能用 Grid 实现,但思路不同,维护性也不同。一般来说:
| 维度 | Flex | Grid |
|---|---|---|
| 适合的布局维度 | 一维 | 二维 |
| 布局控制权 | 子项 | 容器 |
| 响应式灵活度 | 依赖媒体查询 | auto-fit/fill原生支持 |
| 对齐精度 | 轴向对齐 | 精确到格子 |
| 学习曲线 | 中 | 较高 |
| 浏览器支持 | 极好 | 好(IE 需 autoprefixer) |
五、工程实践建议
5.1 不要害怕嵌套
Grid 里嵌套 Flex、Flex 里嵌套 Grid 完全合理,这不是"滥用",而是让每层布局用最适合的工具。
css
复制
/* 外层:Grid 定义页面骨架 */ .page { display: grid; grid-template-areas: ...; } /* 卡片内部:Flex 处理内容排列 */ .card { display: flex; flex-direction: column; justify-content: space-between; }5.2 用 gap 替代 margin
gap(原grid-gap)在 Flex 和 Grid 中都可用,且不会在首尾产生多余间距,比margin更干净:
css
复制
/* ✗ 旧做法:每个子项都有右边距,最后一个要用 :last-child 去掉 */ .item { margin-right: 16px; } .item:last-child { margin-right: 0; } /* ✓ 新做法:只在项之间产生间距 */ .container { display: flex; gap: 16px; }5.3 调试技巧:善用浏览器 DevTools
Chrome/Firefox 的 DevTools 对 Grid 和 Flex 都有专用可视化面板:
- Grid:在 Elements 面板点击
grid标签,可高亮显示所有网格线、区域名称 - Flex:选中 flex 容器,点击旁边的弹性盒图标,可实时调整对齐属性
这是真正理解布局计算的最快方式,比盯着代码想象要快 10 倍。
六、总结
Flex 和 Grid 并不是替代关系,而是互补的布局工具。掌握它们的关键不是记住所有属性,而是建立正确的思维模型:
- Flex:你在管理一条流水线,控制子项在一个方向上的排列和弹性
- Grid:你在设计一张版面,先定框架,再填内容
现代 CSS 布局的最佳实践是:Grid 做宏观结构,Flex 做微观排列,gap代替 margin,auto-fit+minmax做响应式。
掌握这四条原则,80% 的布局需求都能优雅解决。
如果你觉得本文有帮助,欢迎点赞收藏!评论区聊聊你在实际项目中遇到的 Flex/Grid 坑,一起交流~