CSS 布局终极指南:Flex 和 Grid 一次搞懂
彻底掌握 CSS Flexbox 和 Grid 两大布局神器,从基础概念到实战案例,让你不再为布局发愁。
CSS 布局终极指南:Flex 和 Grid 一次搞懂
「这个元素怎么居中?」 「为什么左边的元素跑到右边去了?」 「两栏布局怎么做来着?」
CSS 布局曾经是前端开发者的噩梦。float、position、负 margin、clearfix……各种 hack 满天飞。
直到 Flexbox 和 Grid 的出现,布局终于变得简单了。
今天小明带你彻底搞懂这两个布局神器,从此告别布局焦虑。
Flexbox:一维布局之王
什么是 Flexbox?
Flexbox(弹性盒子)是一种一维布局方式,擅长处理单行或单列的元素排列。
.container {
display: flex; /* 开启 flex 布局 */
}
开启后,容器变成 flex 容器,里面的子元素变成 flex 项目。
┌─────────────────────────────────────────┐
│ flex 容器 (container) │
│ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │ item1 │ │ item2 │ │ item3 │ │
│ └───────┘ └───────┘ └───────┘ │
│ │
│ ◀─────── 主轴 (main axis) ──────────▶ │
└─────────────────────────────────────────┘
▲
│ 交叉轴 (cross axis)
▼
主轴与交叉轴
Flexbox 的核心概念是轴:
- 主轴(main axis):项目排列的方向
- 交叉轴(cross axis):垂直于主轴的方向
/* 主轴方向 */
.container {
flex-direction: row; /* 默认,水平从左到右 → */
flex-direction: row-reverse; /* 水平从右到左 ← */
flex-direction: column; /* 垂直从上到下 ↓ */
flex-direction: column-reverse; /* 垂直从下到上 ↑ */
}
容器属性
justify-content:主轴对齐
.container {
display: flex;
justify-content: flex-start; /* 起点对齐(默认)*/
justify-content: flex-end; /* 终点对齐 */
justify-content: center; /* 居中 */
justify-content: space-between; /* 两端对齐,间距相等 */
justify-content: space-around; /* 每个项目两侧间距相等 */
justify-content: space-evenly; /* 所有间距相等 */
}
图示:
flex-start: [A][B][C]
flex-end: [A][B][C]
center: [A][B][C]
space-between: [A] [B] [C]
space-around: [A] [B] [C]
space-evenly: [A] [B] [C]
align-items:交叉轴对齐
.container {
display: flex;
align-items: stretch; /* 拉伸填满(默认)*/
align-items: flex-start; /* 起点对齐 */
align-items: flex-end; /* 终点对齐 */
align-items: center; /* 居中 */
align-items: baseline; /* 基线对齐 */
}
flex-wrap:换行
.container {
display: flex;
flex-wrap: nowrap; /* 不换行(默认)*/
flex-wrap: wrap; /* 换行 */
flex-wrap: wrap-reverse; /* 换行,但反向 */
}
gap:间距
.container {
display: flex;
gap: 20px; /* 所有间距 */
gap: 10px 20px; /* 行间距 列间距 */
row-gap: 10px; /* 行间距 */
column-gap: 20px; /* 列间距 */
}
项目属性
flex-grow:放大比例
当容器有剩余空间时,项目如何瓜分。
.item1 { flex-grow: 1; } /* 占 1 份 */
.item2 { flex-grow: 2; } /* 占 2 份 */
.item3 { flex-grow: 1; } /* 占 1 份 */
/* 剩余空间被分成 1+2+1=4 份 */
/* item1 得 1/4,item2 得 2/4,item3 得 1/4 */
flex-shrink:缩小比例
当容器空间不足时,项目如何收缩。
.item { flex-shrink: 0; } /* 不收缩 */
.item { flex-shrink: 1; } /* 按比例收缩(默认)*/
flex-basis:初始大小
.item { flex-basis: 200px; } /* 初始宽度 200px */
.item { flex-basis: 30%; } /* 初始宽度 30% */
.item { flex-basis: auto; } /* 根据内容决定(默认)*/
flex 简写
/* flex: grow shrink basis */
.item { flex: 0 1 auto; } /* 默认值 */
.item { flex: 1; } /* 等于 flex: 1 1 0% */
.item { flex: auto; } /* 等于 flex: 1 1 auto */
.item { flex: none; } /* 等于 flex: 0 0 auto */
align-self:单独对齐
.item {
align-self: auto; /* 继承容器的 align-items */
align-self: flex-start;
align-self: flex-end;
align-self: center;
align-self: stretch;
}
Flexbox 实战案例
案例 1:完美居中
.container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 100vh;
}
这是最简单的居中方式,告别 position: absolute + transform。
案例 2:导航栏
<nav class="navbar">
<div class="logo">Logo</div>
<ul class="nav-links">
<li>首页</li>
<li>产品</li>
<li>关于</li>
</ul>
<button class="login-btn">登录</button>
</nav>
.navbar {
display: flex;
justify-content: space-between; /* logo 左边,按钮右边 */
align-items: center;
padding: 0 20px;
height: 60px;
}
.nav-links {
display: flex;
gap: 20px;
list-style: none;
}
案例 3:卡片列表自适应
.card-list {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 300px; /* 最小 300px,可放大,可换行 */
max-width: 400px;
}
案例 4:底部固定的页脚
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* 主内容区占据剩余空间 */
}
footer {
/* 自动被推到底部 */
}
Grid:二维布局之王
什么是 Grid?
Grid 是一种二维布局方式,可以同时处理行和列。
.container {
display: grid;
}
如果说 Flexbox 是「一维的」,Grid 就是「二维的」:
Flexbox(一维):
┌───┐┌───┐┌───┐
│ 1 ││ 2 ││ 3 │
└───┘└───┘└───┘
Grid(二维):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘
定义网格
grid-template-columns:列
.container {
display: grid;
/* 三列,每列 200px */
grid-template-columns: 200px 200px 200px;
/* 三列,等分 */
grid-template-columns: 1fr 1fr 1fr;
/* 简写 */
grid-template-columns: repeat(3, 1fr);
/* 混合 */
grid-template-columns: 200px 1fr 2fr;
/* 自适应列数 */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
grid-template-rows:行
.container {
display: grid;
grid-template-rows: 100px 200px 100px;
grid-template-rows: 1fr 2fr 1fr;
grid-template-rows: repeat(3, 100px);
}
gap:间距
.container {
display: grid;
gap: 20px; /* 行列间距都是 20px */
gap: 10px 20px; /* 行间距 10px,列间距 20px */
row-gap: 10px;
column-gap: 20px;
}
fr 单位
fr 是 Grid 的特殊单位,表示可用空间的份数。
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
/* 第一列占 1/4,第二列占 2/4,第三列占 1/4 */
}
项目定位
自动放置
默认情况下,项目按顺序放入网格。
手动定位
.item {
grid-column-start: 1; /* 从第 1 列线开始 */
grid-column-end: 3; /* 到第 3 列线结束 */
grid-row-start: 1;
grid-row-end: 2;
/* 简写 */
grid-column: 1 / 3; /* 跨越第 1-2 列 */
grid-row: 1 / 2;
/* 更简写 */
grid-area: 1 / 1 / 2 / 3; /* row-start / col-start / row-end / col-end */
/* 用 span 表示跨越 */
grid-column: 1 / span 2; /* 从第 1 列开始,跨 2 列 */
}
网格线编号
列线: 1 2 3 4
│ │ │ │
▼ ▼ ▼ ▼
┌─────┬─────┬─────┐ ← 行线 1
│ 1 │ 2 │ 3 │
├─────┼─────┼─────┤ ← 行线 2
│ 4 │ 5 │ 6 │
└─────┴─────┴─────┘ ← 行线 3
区域命名
可以给网格区域起名字,让布局更直观。
.container {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 60px 1fr 60px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
对齐方式
justify-items / align-items:项目在格子内的对齐
.container {
display: grid;
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
/* 简写 */
place-items: center center;
}
justify-content / align-content:整个网格在容器内的对齐
.container {
display: grid;
justify-content: start | end | center | space-between | space-around;
align-content: start | end | center | space-between | space-around;
/* 简写 */
place-content: center center;
}
Grid 实战案例
案例 1:经典三栏布局
.layout {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 60px 1fr 60px;
min-height: 100vh;
gap: 10px;
}
.header { grid-column: 1 / -1; } /* 跨越所有列 */
.footer { grid-column: 1 / -1; }
案例 2:响应式图片画廊
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
.gallery img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
}
auto-fill + minmax 是响应式布局的黄金组合:
- 最小 250px
- 最大 1fr(等分剩余空间)
- 自动决定每行放几个
案例 3:仪表盘布局
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 200px);
gap: 20px;
}
/* 大卡片跨越多个格子 */
.card-large {
grid-column: span 2;
grid-row: span 2;
}
.card-wide {
grid-column: span 2;
}
.card-tall {
grid-row: span 2;
}
案例 4:圣杯布局
.holy-grail {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
@media (max-width: 768px) {
.holy-grail {
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
grid-template-columns: 1fr;
}
}
Flexbox vs Grid:什么时候用哪个?
| 场景 | 推荐 | 原因 |
|---|---|---|
| 导航栏 | Flexbox | 一维排列 |
| 卡片列表 | 两者皆可 | Flexbox 更简单 |
| 页面整体布局 | Grid | 二维控制更方便 |
| 项目居中 | Flexbox | 代码更少 |
| 复杂仪表盘 | Grid | 可精确控制位置 |
| 表单布局 | Grid | 对齐更方便 |
简单原则:
- 一维排列 → Flexbox
- 二维布局 → Grid
- 不确定 → 先试 Flexbox,不行再换 Grid
它们也可以组合使用:
/* Grid 做页面布局 */
.page {
display: grid;
grid-template-columns: 200px 1fr;
}
/* Flexbox 做组件内部布局 */
.card {
display: flex;
flex-direction: column;
gap: 10px;
}
常用布局速查表
水平居中
/* 块级元素 */
.center { margin: 0 auto; }
/* Flex */
.parent { display: flex; justify-content: center; }
/* Grid */
.parent { display: grid; place-items: center; }
垂直居中
/* Flex */
.parent {
display: flex;
align-items: center;
min-height: 100vh;
}
/* Grid */
.parent {
display: grid;
place-items: center;
min-height: 100vh;
}
两栏布局(左固定右自适应)
/* Flex */
.container {
display: flex;
}
.left { width: 200px; }
.right { flex: 1; }
/* Grid */
.container {
display: grid;
grid-template-columns: 200px 1fr;
}
等高列
/* Flex 默认就是等高 */
.container {
display: flex;
}
/* Grid 也是 */
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
底部固定
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main { flex: 1; }
总结
Flexbox 核心:
display: flex开启flex-direction控制方向justify-content主轴对齐align-items交叉轴对齐flex: 1让项目填满剩余空间
Grid 核心:
display: grid开启grid-template-columns/rows定义网格fr单位表示份数gap设置间距grid-area命名区域
选择原则:
- 一维用 Flex,二维用 Grid
- 简单场景用 Flex,复杂场景用 Grid
- 两者可以组合使用
掌握这两个布局工具,你就能轻松应对 90% 的布局需求。
小明冷笑话收尾:
问:CSS 布局最难的是什么? 答:垂直居中。
问:有了 Flexbox 之后呢? 答:记住
display: flex; justify-content: center; align-items: center;这三行代码价值一万块,因为它能让你少掉一万根头发。
「布局不难,难的是记住这些属性名。」—— 小明