做前端少不了和布局打交道。早期我们用 float、position 硬凑,margin 塌陷、垂直居中让人头大。如今 CSS Grid 与 Flexbox 已成为现代网页布局的事实标准:Flexbox 擅长一维排列,Grid 擅长二维网格。本文用可运行的代码示例,讲清两者核心概念、常见组合与避坑要点,帮你彻底摆脱”布局靠猜”的焦虑。
一、Flexbox:一维布局的主力
Flexbox(弹性盒)解决的是单方向的排列问题——要么横着排,要么竖着排。它最适合导航栏、按钮组、卡片列表这类”一行/一列”场景。理解 Flexbox 只需抓住两个角色:容器(flex container)和子项(flex item)。
1.1 主轴与交叉轴
display: flex 让元素变成弹性容器,默认主轴是水平方向(从左到右)。justify-content 管主轴对齐,align-items 管交叉轴对齐。这是 90% 布局需求的核心。
.nav {
display: flex;
justify-content: space-between; /* 主轴:两端对齐 */
align-items: center; /* 交叉轴:垂直居中 */
gap: 16px; /* 子项间距,替代 margin */
}
.nav a {
padding: 8px 12px;
text-decoration: none;
}
上面这段就能做出一个两端对齐、垂直居中的导航栏。gap 是现代布局的神器,它不会在首尾产生多余间距,比 margin 干净得多。
1.2 子项如何”抢地盘”:flex 三兄弟
子项的伸缩由三个属性控制:flex-grow(放大比例)、flex-shrink(缩小比例)、flex-basis(基准尺寸)。日常用简写 flex: 1 表示”有空位就均分,没空位就收缩”。
.sidebar { flex: 0 0 240px; } /* 不伸不缩,固定 240px */
.main { flex: 1; } /* 占据剩余全部空间 */
.aside { flex: 0 0 200px; } /* 固定 200px */
/* 等分布局:三个卡片各占 1 份 */
.card { flex: 1 1 0; }
二、CSS Grid:二维布局的终极方案
当布局需要同时管行和列(比如后台管理页、相册、仪表盘),Grid 比 Flexbox 更直观。Grid 把容器划分成看不见的网格线,子项可以精确指定”从第几行第几列到第几行第几列”。
2.1 定义行列与 fr 单位
grid-template-columns 定义列,grid-template-rows 定义行。fr(fraction,分数)是 Grid 专属单位,表示”剩余空间的占比”,类似 Flexbox 的 flex: 1。
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 三等分三列 */
gap: 12px;
}
/* 响应式:窄屏自动变一列 */
@media (max-width: 600px) {
.gallery { grid-template-columns: 1fr; }
}
repeat(3, 1fr) 是”重复三次 1fr”的简写,比手写 1fr 1fr 1fr 优雅。想把某张图横跨两列?用 grid-column: span 2 即可,这是 Flexbox 很难优雅做到的。
很多新手会问:为什么不直接用 float 或 display: inline-block 老办法?答案是”可控性”和”心智负担”。float 本质是图文环绕,拿来做布局需要清除浮动、处理高度塌陷,稍不留神整页错乱;inline-block 则会被空白字符撑出诡异间隙。Flexbox 与 Grid 是专门为布局而生的模型,对齐、间距、换行都是一等公民,调试时一眼能看懂,这也是它们能取代老方案的根本原因。
2.2 经典后台布局:一行 Grid 搞定
.layout {
display: grid;
grid-template-columns: 200px 1fr 240px; /* 侧栏 | 主区 | 右栏 */
grid-template-rows: 56px 1fr 40px; /* 顶栏 | 主体 | 底栏 */
grid-template-areas:
"header header header"
"side main right"
"footer footer footer";
height: 100vh;
}
.header { grid-area: header; }
.side { grid-area: side; }
.main { grid-area: main; overflow: auto; }
grid-template-areas 用”可视化字符串”描述布局,改结构时改这几行字就行,可读性远胜一堆 float 和负 margin。
三、Grid 与 Flexbox 怎么选
一句话经验:宏观骨架用 Grid,微观排列用 Flexbox。Grid 负责”页面有几行几列、各部分占哪块”,Flexbox 负责”这块里的内容怎么对齐”。两者不是替代关系,而是搭档。
| 维度 | Flexbox | CSS Grid |
| 布局方向 | 一维(行或列) | 二维(行列同时) |
| 典型场景 | 导航栏、卡片列表、按钮组 | 页面骨架、相册、仪表盘 |
| 对齐能力 | 靠主轴/交叉轴 | 靠网格线/区域命名 |
| 内容驱动 | ✅ 子项尺寸可自适应内容 | ⚠️ 更适合先定轨道再放内容 |
| 上手难度 | 低,概念少 | 中,属性多但更强大 |
四、组合实战:卡片列表里再嵌套 Flex
真实项目几乎都是组合使用:Grid 负责把卡片排成网格,每张卡片内部用 Flexbox 安排图标、标题和按钮的位置。
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 16px;
}
.card {
display: flex;
flex-direction: column; /* 卡片内纵向排列 */
padding: 16px;
}
.card .footer {
margin-top: auto; /* 把按钮推到卡片底部 */
display: flex;
justify-content: flex-end;
}
repeat(auto-fill, minmax(260px, 1fr)) 是响应式排版的黄金写法:容器够宽就多列、不够就少列,完全不需要媒体查询。margin-top: auto 则保证不同高度的卡片,按钮都贴底对齐。
五、常见坑与排障
| 现象 | 原因 | 解决 |
| 子项被强行拉伸占满整行 | Grid 默认 align-items: stretch | 设 align-items: start 或给子项固定高 |
| Flex 子项溢出容器 | 内容最小尺寸撑开 | 加 min-width: 0 允许收缩 |
| 左右留白对不齐 | 误用 margin 而非 gap | 改用 gap |
| Grid 列宽不按比例 | 混用了固定 px 和 fr | 统一用 fr,或 minmax() 兜底 |
| 垂直居中失败 | 只对父级设了 align | 确认父级是 flex/grid 容器 |
最容易被忽略的是 min-width: 0:Flex 子项默认最小宽度是内容宽度,遇到长文本或代码会撑破布局,加一句 min-width: 0 就能让它正常收缩换行。
六、性能注意:布局变化会触发重排
Grid 和 Flexbox 的几何计算属于浏览器的重排(reflow)阶段。频繁改 width、gap、flex-basis 会反复触发重排,在长列表里卡顿明显。优化原则:动画尽量用 transform 和 opacity(只触发合成,不重排),把布局类属性留在静态样式里。
想系统练手,可以用 Vite 前端构建工具实战 起一个本地项目,把上面的示例逐段敲一遍;布局进阶可看 CSS 容器查询响应式布局,它和 Grid/Flexbox 配合能做出真正自适应的组件;若你在 Vue3 单文件组件 里写样式,这些写法同样直接可用。对重排重绘原理感兴趣的,推荐延伸阅读 浏览器渲染:关键路径与重排重绘。
结语
CSS Grid 与 Flexbox 早已不是”新特性”,而是每个前端每天的日常工具。记住口诀:二维骨架用 Grid,一维排列用 Flexbox,响应式优先用 auto-fill + minmax。把本文的示例存进你的代码片段库,下次遇到布局需求,先想清楚”这是一行还是一张网”,选对工具,事情就成了一半。
如果想用现代框架组织这些组件,前面提到的 Vue3 与 Vite 两篇可以直接衔接;容器查询则能在 Grid 网格内再细粒度控制每个卡片的响应式表现,三者叠加才是当下最顺手的布局组合。
七、30 秒上手清单
把下面这张清单贴在编辑器旁边,遇到布局先从这里过一遍:① 先看是”一行”还是”一张网”——一行选 Flexbox,二维选 Grid;② 间距永远优先用 gap,别再手写 margin;③ 响应式首选 repeat(auto-fill, minmax(260px, 1fr)),能不写媒体查询就不写;④ 子项溢出先加 min-width: 0;⑤ 需要贴底对齐用 margin-top: auto;⑥ 动画避开支局属性,用 transform 保性能。把这六条变成肌肉记忆,八成的日常布局都能在十分钟内搞定。




