CSS Flexbox 弹性布局
这一课你将能做到
- 使用 Flexbox 实现水平居中、垂直居中、等分布局、两端对齐等常见布局需求
- 理解主轴(main axis)与交叉轴(cross axis)的概念,并正确使用
justify-content、align-items、align-self - 构建 CodeForge 风格的响应式导航栏和课程卡片列表,掌握
flex-grow、flex-shrink、flex-basis的分配逻辑
为什么要学
在 Flexbox 出现之前,前端用 float、position、inline-block 和表格布局来模拟行列排列,代码脆弱且充满 hack(如清除浮动、垂直居中需要 position: absolute + 负 margin)。Flexbox 是 CSS 第一个专门为「一维布局」设计的现代方案——无论是水平排列的导航链接,还是垂直排列的表单字段,或是需要在容器中自动分配剩余空间的卡片列表,Flexbox 都能用声明式语法优雅解决。
CodeForge 的顶部导航栏需要 logo 居左、菜单居中、用户头像居右;课程卡片需要等宽排列且高度一致;登录表单需要垂直居中于屏幕。Flexbox 用几行声明就能解决这些过去需要几十行 hack 的问题。
先建立图像
Flex 容器与 Flex 项目:
+--------------------------------------------------+
| [项目1] [项目2] [项目3] [项目4] | ← 主轴 (main axis),默认水平
+--------------------------------------------------+
↑
交叉轴 (cross axis),默认垂直
容器控制整体排列:justify-content(主轴)、align-items(交叉轴)
项目控制自身行为:align-self(交叉轴覆盖)、flex-grow/shrink/basis(尺寸分配)
跟着做
步骤 1:创建 Flex 容器与基础排列
创建 flexbox.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flexbox 练习</title>
<style>
:root { --primary: #2563eb; --surface: #fff; --border: #e2e8f0; --text: #0f172a; }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; padding: 2rem; background: #f1f5f9; color: var(--text); }
.demo-section { margin-bottom: 3rem; }
.demo-title { font-size: 1.125rem; margin-bottom: 1rem; }
.flex-container { display: flex; gap: 1rem; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 1rem; }
.flex-item { background: var(--primary); color: white; padding: 1rem 1.5rem; border-radius: 8px; font-weight: 500; }
</style>
</head>
<body>
<h1>Flexbox 基础演示</h1>
<section class="demo-section">
<h2 class="demo-title">1. 默认水平排列</h2>
<div class="flex-container">
<div class="flex-item">课程 A</div>
<div class="flex-item">课程 B</div>
<div class="flex-item">课程 C</div>
</div>
</section>
<section class="demo-section">
<h2 class="demo-title">2. 垂直排列(flex-direction: column)</h2>
<div class="flex-container" style="flex-direction: column;">
<div class="flex-item">第一课</div>
<div class="flex-item">第二课</div>
<div class="flex-item">第三课</div>
</div>
</section>
</body>
</html>
打开页面观察:display: flex 让子元素默认水平排列;flex-direction: column 切换为垂直排列。gap: 1rem 设置项目间距,比逐个加 margin-right 更简洁。
步骤 2:主轴对齐 justify-content
<div class="flex-container" style="justify-content: flex-start;">...</div>
<div class="flex-container" style="justify-content: center;">...</div>
<div class="flex-container" style="justify-content: space-between;">...</div>
flex-start(默认):向主轴起点对齐center:向主轴中心对齐space-between:两端对齐,项目间距相等space-around:项目两侧间距相等space-evenly:所有间距完全相等
步骤 3:交叉轴对齐 align-items 与 align-self
<div class="flex-container" style="align-items: stretch; height: 120px;">...</div>
<div class="flex-container" style="align-items: flex-start; height: 120px;">...</div>
<div class="flex-container" style="align-items: center; height: 120px;">...</div>
align-items 控制所有项目在交叉轴上的对齐。单个项目可用 align-self 覆盖,如 align-self: flex-end。
步骤 4:尺寸分配 flex-grow、flex-shrink、flex-basis
<div class="flex-item" style="flex: 1;">flex: 1(等分)</div>
<div class="flex-item" style="flex: 2;">flex: 2(占 2/4)</div>
<div class="flex-item" style="flex: 0 0 200px;">固定 200px</div>
<div class="flex-item" style="flex: 1;">填充剩余</div>
flex: 1 是 flex: 1 1 0% 的缩写,表示可伸展、可收缩、基准为 0。flex: 0 0 200px 表示固定 200px,不伸展不收缩。
步骤 5:实战——CodeForge 响应式导航栏
<nav style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1.5rem;">
<a href="#" style="font-weight: 700; color: var(--primary);">CodeForge</a>
<ul style="display: flex; gap: 1.5rem; list-style: none; align-items: center;">
<li><a href="#">课程</a></li>
<li><a href="#">路线图</a></li>
<li><a href="#">社区</a></li>
</ul>
<div style="display: flex; gap: 0.75rem; align-items: center;">
<button>登录</button>
<button>注册</button>
</div>
</nav>
用 justify-content: space-between 实现三段分布,align-items: center 垂直居中,嵌套 Flex 实现中间菜单和右侧按钮组。
讲清楚要点
-
Flexbox 是一维布局:它擅长处理「一行」或「一列」的排列。如果你需要同时控制行和列(如卡片网格),应使用 CSS Grid。两者可嵌套使用:Grid 负责整体页面骨架,Flex 负责卡片内部元素排列。
-
gap优于margin:Flex 容器支持gap: 1rem设置项目间距,自动处理首尾项目的边缘问题,比手动给每个项目加margin-right: 1rem再处理最后一个元素的margin-right: 0优雅得多。 -
margin: auto在 Flex 中的妙用:给单个 Flex 项目设置margin-left: auto,它会吸收主轴上所有剩余空间,把该项目推到最右侧。这是实现「logo 居左,按钮居右」的另一种方式。 -
flex-wrap处理溢出:默认flex-wrap: nowrap,项目会被压缩到一行。设置flex-wrap: wrap后,空间不足时自动换行。配合flex: 1 1 300px,可实现「每行至少 300px,自动换行」的响应式卡片列表。 -
Flex 项目的
min-width: auto陷阱:Flex 项目的默认min-width是auto(等于内容最小宽度),导致长文本或长 URL 可能撑破容器。解决方案:给项目设置min-width: 0或overflow: hidden。 -
主轴与交叉轴随
flex-direction变化:flex-direction: column时,主轴变为垂直方向,justify-content控制垂直对齐,align-items控制水平对齐。写代码前先在脑中确认当前主轴方向。
你可能会懵的地方
-
「
justify-content和align-items到底哪个管水平?」 取决于flex-direction。默认row时,justify-content管水平(主轴),align-items管垂直(交叉轴)。改成column后完全反过来。记忆方法:justify永远沿主轴,align永远沿交叉轴。 -
「
flex: 1和width: 100%有什么区别?」flex: 1让项目参与剩余空间分配,多个flex: 1的项目平分空间。width: 100%是固定尺寸声明,在 Flex 容器中可能被flex-shrink压缩。Flex 布局中优先用flex属性控制尺寸。 -
「垂直居中到底有多少种写法?」 Flex 方案:容器
display: flex; align-items: center; justify-content: center;。Grid 方案:容器display: grid; place-items: center;。传统方案:position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);。现代开发优先 Flex 或 Grid。 -
「Flex 和 Grid 怎么选?」 一维排列(导航栏、表单行、按钮组)用 Flex。二维网格(卡片矩阵、整体页面布局)用 Grid。复杂页面通常两者结合:Grid 定义页面骨架,Flex 定义组件内部排列。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
用 float 做导航栏布局 | 需要清除浮动,代码脆弱 | 用 display: flex |
给每个 Flex 项目加 margin-right 做间距 | 需要处理最后一个元素的 margin-right: 0 | 用容器 gap 属性 |
用 position: absolute 做垂直居中 | 脱离文档流,响应式困难 | 用 Flex 的 align-items: center + justify-content: center |
flex: 1 项目被长内容撑破 | 未设置 min-width: 0 | 给项目加 min-width: 0 或 overflow: hidden |
在 Flex 项目中用 width: 100% 代替 flex: 1 | 失去弹性分配能力 | 用 flex: 1 或 flex-grow: 1 |
忽略 flex-wrap 导致内容被压缩 | 项目被挤压变形 | 设置 flex-wrap: wrap 并给项目设置最小基准宽度 |
卡点急救
-
Flex 项目没有按预期排列:检查容器是否设置了
display: flex。检查主轴方向——flex-direction: column时justify-content控制的是垂直方向。在开发者工具中给容器加临时outline: 1px solid red确认容器边界。 -
项目内容溢出容器:Flex 项目的默认
min-width: auto会阻止收缩到比内容更窄。给项目设置min-width: 0,或给内容设置overflow-wrap: break-word。 -
想让最后一个项目靠右,但
justify-content: space-between影响了其他项目:不要动容器的justify-content。给目标项目单独设置margin-left: auto,它会吸收所有剩余空间把自己推到最右侧。
面试常问
-
「Flexbox 中
justify-content和align-items的区别?」justify-content控制项目在主轴上的对齐方式,默认主轴是水平方向(flex-direction: row)。align-items控制项目在交叉轴上的对齐方式,默认交叉轴是垂直方向。当flex-direction: column时,主轴变为垂直,justify-content控制垂直对齐,align-items控制水平对齐。 -
「
flex: 1代表什么?三个参数分别是什么?」flex: 1是flex: 1 1 0%的缩写。三个参数依次是:flex-grow(伸展因子,决定如何分配剩余空间)、flex-shrink(收缩因子,决定空间不足时如何压缩)、flex-basis(基准尺寸,分配前的初始大小)。flex: 1表示项目从 0 基准开始,等分所有剩余空间。 -
「如何实现一个圣杯布局(header、footer、三列中间自适应)?」 现代方案用 Flex 或 Grid。Flex 方案:body 设为
display: flex; flex-direction: column; min-height: 100vh,中间区域flex: 1吸收剩余高度。中间三列再用 Flex 或 Grid:两侧固定宽度,中间flex: 1自适应。Grid 方案更简洁:grid-template-rows: auto 1fr auto; grid-template-columns: 200px 1fr 200px;。
自测三问
- 一个 Flex 容器中有三个项目,如何让第一个项目靠左、后两个项目靠右?
flex-direction: column时,justify-content: center和align-items: center分别控制什么方向的对齐?- 为什么 Flex 项目中的长文本(如 URL)有时会撑破容器?如何解决?
小结一句话
Flexbox 用「容器控制排列方向与对齐,项目控制自身尺寸与顺序」的声明式模型,彻底解决了 CSS 一维布局的历史难题;掌握主轴/交叉轴思维和 flex 三参数,就能写出健壮、响应式的现代界面。
延伸
- MDN:Flexbox 基础概念
- MDN:Flex 容器属性
- CSS-Tricks:A Complete Guide to Flexbox
- 下一课:CSS Grid——二维布局的终极方案。