Flexbox 布局
约 3730 字大约 12 分钟
cssflexboxlayout
2026-04-16
1. Flexbox 简介
Flexbox 是 CSS3 弹性盒子布局模块(Flexible Box Layout Module)的缩写,是一种一维布局模型,用于在容器中分配空间和对齐元素。
为什么需要 Flexbox
在 Flexbox 出现之前,实现以下常见布局往往需要借助浮动(float)、定位(position)或 display: table 等hack手段:
- 垂直居中元素
- 让元素填满容器剩余空间
- 实现响应式卡片网格
- 改变元素顺序而不影响 HTML 结构
传统布局方式存在诸多痛点:
- 浮动布局需要清除浮动,且会影响后续元素
- 定位布局会脱离文档流,难以实现自适应
- 表格布局语义不明确,不适合复杂场景
Flexbox 提供了一种更简洁、更强大的方式来处理这些常见布局问题。
核心概念
Flexbox 布局中有两个基本概念:
- 容器(Container):使用
display: flex或display: inline-flex的元素 - 项目(Items):容器的直接子元素
┌─────────────────────────────────────┐
│ flex container │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │item1│ │item2│ │item3│ │item4│ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
└─────────────────────────────────────┘2. 容器属性
2.1 display
display 属性定义元素是否为弹性盒子。
| 值 | 描述 |
|---|---|
flex | 生成块级弹性盒子,元素独占一行 |
inline-flex | 生成行内弹性盒子,元素可以与其他行内元素共处一行 |
/* 块级弹性容器 */
.container {
display: flex;
}
/* 行内弹性容器 */
.container {
display: inline-flex;
}注意:设置
display: flex后,容器的子元素自动成为弹性项目(flex items),但这不会影响元素本身的显示类型(block 或 inline)。
2.2 flex-direction
flex-direction 指定主轴方向,即弹性项目的排列方向。
| 值 | 描述 |
|---|---|
row(默认) | 从左到右水平排列 |
row-reverse | 从右到左水平排列 |
column | 从上到下垂直排列 |
column-reverse | 从下到上垂直排列 |
row: item1 → item2 → item3 →
row-reverse: ← item1 ← item2 ← item3
column: item1
↓
item2
↓
item3.container {
flex-direction: row; /* 默认:水平从左到右 */
flex-direction: row-reverse; /* 水平从右到左 */
flex-direction: column; /* 垂直从上到下 */
flex-direction: column-reverse; /* 垂直从下到上 */
}2.3 flex-wrap
默认情况下,所有弹性项目都排在一条轴线上。flex-wrap 控制项目是否换行。
| 值 | 描述 |
|---|---|
nowrap(默认) | 不换行,项目会被压缩以适应容器宽度 |
wrap | 换行,第一行在上方 |
wrap-reverse | 换行,第一行在下方 |
nowrap (不换行,项目被压缩):
┌───────────────────────────────┐
│item1│item2│item3│item4│item5│
└───────────────────────────────┘
wrap (换行):
┌───────────────────────────────┐
│item1│item2│item3│ │
├───────────────────────────────┤
│item4│item5│ │
└───────────────────────────────┘.container {
flex-wrap: nowrap; /* 默认:不换行 */
flex-wrap: wrap; /* 换行 */
flex-wrap: wrap-reverse; /* 反转换行顺序 */
}2.4 flex-flow
flex-flow 是 flex-direction 和 flex-wrap 的简写。
.container {
/* flex-flow: <flex-direction> <flex-wrap> */
flex-flow: row wrap; /* 常用组合:水平排列 + 换行 */
flex-flow: column nowrap; /* 垂直排列 + 不换行 */
}2.5 justify-content
justify-content 定义主轴上项目的对齐方式(主轴方向由 flex-direction 决定)。
| 值 | 描述 |
|---|---|
flex-start(默认) | 左对齐 / 上对齐 |
flex-end | 右对齐 / 下对齐 |
center | 居中对齐 |
space-between | 两端对齐,项目间距相等 |
space-around | 每个项目两侧间距相等(项目之间间距是边缘的2倍) |
space-evenly | 所有间距完全相等 |
justify-content: flex-start justify-content: center
┌────────────────────────┐ ┌────────────────────────┐
│item1 item2 item3 │ │ item1 item2 item3 │
└────────────────────────┘ └────────────────────────┘
justify-content: space-between justify-content: space-around
┌────────────────────────┐ ┌────────────────────────┐
│item1 item2 item3 │ │ item1 item2 item3 │
└────────────────────────┘ └────────────────────────┘.container {
justify-content: flex-start; /* 默认:起点对齐 */
justify-content: center; /* 居中 */
justify-content: flex-end; /* 终点对齐 */
justify-content: space-between; /* 两端对齐 */
justify-content: space-around; /* 环绕对齐 */
justify-content: space-evenly; /* 均等对齐 */
}2.6 align-items
align-items 定义项目在交叉轴上的对齐方式(交叉轴垂直于主轴)。
| 值 | 描述 |
|---|---|
stretch(默认) | 如果项目未设置高度或设为 auto,将占满整个容器高度 |
flex-start | 交叉轴起点对齐 |
flex-end | 交叉轴终点对齐 |
center | 交叉轴居中对齐 |
baseline | 项目基线对齐 |
align-items: stretch (项目拉伸至容器高度):
┌────────────────────┐
│ ████████████████ │
│ ████████████████ │
│ ████████████████ │
└────────────────────┘
align-items: center (交叉轴居中):
┌────────────────────┐
│ │
│ item1 item2 item3 │
│ │
└────────────────────┘
align-items: flex-start:
┌────────────────────┐
│ item1 item2 item3 │
│ │
│ │
└────────────────────┘.container {
align-items: stretch; /* 默认:拉伸 */
align-items: flex-start; /* 交叉轴起点 */
align-items: flex-end; /* 交叉轴终点 */
align-items: center; /* 交叉轴居中 */
align-items: baseline; /* 基线对齐 */
}2.7 align-content
align-content 定义多根轴线(多行)在交叉轴上的对齐方式。只有当 flex-wrap: wrap 且项目换行后才生效。
| 值 | 描述 |
|---|---|
stretch(默认) | 轴线拉伸以填满剩余空间 |
flex-start | 所有行向交叉轴起点对齐 |
flex-end | 所有行向交叉轴终点对齐 |
center | 所有行向交叉轴居中对齐 |
space-between | 两端对齐,行间距相等 |
space-around | 每行两侧间距相等 |
align-content: space-between:
┌────────────────────────┐
│ item1 item2 item3 │
├────────────────────────┤
│ item4 item5 │
└────────────────────────┘
align-content: center:
┌────────────────────────┐
│ │
│ item1 item2 item3 │
│ item4 item5 │
│ │
└────────────────────────┘.container {
align-content: stretch; /* 默认:拉伸 */
align-content: flex-start; /* 起点对齐 */
align-content: flex-end; /* 终点对齐 */
align-content: center; /* 居中 */
align-content: space-between; /* 两端对齐 */
align-content: space-around; /* 环绕对齐 */
}2.8 gap
gap 属性设置弹性项目之间的间距。
| 属性 | 描述 |
|---|---|
row-gap | 设置行间距 |
column-gap | 设置列间距 |
gap | row-gap 和 column-gap 的简写 |
.container {
/* 单独设置 */
row-gap: 20px; /* 行间距 */
column-gap: 30px; /* 列间距 */
/* 简写:一个值表示行列间距相同 */
gap: 20px;
/* 两个值:行间距 列间距 */
gap: 20px 30px;
}注意:
gap不会在容器边缘添加间距,只会作用于项目之间。
3. 项目属性
3.1 flex-grow
flex-grow 定义项目的放大比例,默认为 0,表示不放大。
- 如果所有项目的
flex-grow都为1,则它们将平分剩余空间 - 如果某个项目的
flex-grow为2,其他项目为1,则前者占用的剩余空间是后者的两倍
.item {
flex-grow: 0; /* 默认:不放大 */
flex-grow: 1; /* 等比分配剩余空间 */
flex-grow: 2; /* 占用2份 */
}3.2 flex-shrink
flex-shrink 定义项目的缩小比例,默认为 1,表示空间不足时项目将缩小。
- 如果所有项目的
flex-shrink都为1,空间不足时将等比缩小 - 如果某个项目的
flex-shrink为0,则不缩小
.item {
flex-shrink: 1; /* 默认:允许缩小 */
flex-shrink: 0; /* 不缩小,保持原尺寸 */
}3.3 flex-basis
flex-basis 定义在分配多余空间之前,项目占据的主轴空间。默认为 auto,即项目本来的大小。
.item {
flex-basis: auto; /* 默认:根据内容计算尺寸 */
flex-basis: 200px; /* 固定宽度 */
flex-basis: 50%; /* 百分比 */
}3.4 flex
flex 是 flex-grow、flex-shrink 和 flex-basis 的简写。
| 单值语法 | 等同于 | 备注 |
|---|---|---|
flex: initial | flex: 0 1 auto | 初始值,不放大,可缩小 |
flex: 0 | flex: 0 1 0% | 不放大,不缩小,使用0宽度 |
flex: none | flex: 0 0 auto | 不放大,不缩小,保持原尺寸 |
flex: 1 | flex: 1 1 0% | 可放大可缩小,灵活尺寸 |
flex: auto | flex: 1 1 auto | 可放大可缩小,基于内容 |
.item {
flex: initial; /* 不放大,可缩小(常用) */
flex: none; /* 不变化 */
flex: 1; /* 占满剩余空间(常用) */
flex: auto; /* 可放大可缩小 */
}建议:优先使用
flex简写,而不是分别设置三个属性,因为简写能更智能地处理默认值。
3.5 align-self
align-self 允许单个项目有与其他项目不同的对齐方式,会覆盖 align-items 的值。
| 值 | 描述 |
|---|---|
auto(默认) | 继承父容器的 align-items 值 |
stretch | 拉伸至填满容器 |
flex-start | 交叉轴起点对齐 |
flex-end | 交叉轴终点对齐 |
center | 交叉轴居中对齐 |
baseline | 基线对齐 |
.item {
align-self: auto; /* 默认:继承父容器 */
align-self: flex-start; /* 单独设置起点对齐 */
align-self: center; /* 单独设置居中 */
}3.6 order
order 定义项目的排列顺序,数值越小越靠前,默认为 0。
.item {
order: 0; /* 默认顺序 */
order: -1; /* 排在最前面 */
order: 1; /* 排在后面 */
}注意:
order只改变视觉顺序,不改变 DOM 结构和语义顺序,对可访问性有重要影响。
4. 主轴与交叉轴
理解 Flexbox 的关键在于理解两条轴线:
主轴(Main Axis)
- 由
flex-direction属性定义 flex-direction: row / row-reverse时,主轴是水平方向(从左到右 / 从右到左)flex-direction: column / column-reverse时,主轴是垂直方向(从上到下 / 从下到上)justify-content属性作用于主轴
交叉轴(Cross Axis)
- 始终垂直于主轴
- 如果主轴是水平方向,交叉轴就是垂直方向
- 如果主轴是垂直方向,交叉轴就是水平方向
align-items和align-content属性作用于交叉轴
flex-direction: row (默认)
主轴 →→→→→→→→→→→→→→→→→→→→→→→
item1 item2 item3
交叉轴
↓
↓
↓
flex-direction: column
交叉轴 →→→→→→→→→→→→→→→→→→→→→→→
item1
主轴 item2
↓ item3
↓
↓5. 常用布局场景
5.1 居中布局
Flexbox 最常见的用法之一就是实现元素居中,这是传统 CSS 很难完美解决的问题。
/* 水平垂直居中 */
.parent {
display: flex;
justify-content: center;
align-items: center;
}
/* 仅水平居中 */
.parent {
display: flex;
justify-content: center;
}
/* 仅垂直居中 */
.parent {
display: flex;
align-items: center;
}<div class="parent">
<div class="child">居中内容</div>
</div>5.2 导航栏
使用 Flexbox 可以轻松实现各种导航栏布局。
/* 均等分布导航 */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
/* 左中右布局 */
.navbar {
display: flex;
justify-content: space-between;
}
.navbar .left,
.navbar .right {
display: flex;
gap: 16px;
}
.navbar .logo {
/* 自动占据中间剩余空间 */
flex: 1;
text-align: center;
}<!-- 均等分布导航 -->
<nav class="navbar">
<a href="#">首页</a>
<a href="#">产品</a>
<a href="#">关于</a>
<a href="#">联系</a>
</nav>
<!-- 左中右布局 -->
<nav class="navbar">
<div class="left">
<span>logo</span>
</div>
<div class="logo">中间标题</div>
<div class="right">
<span>用户</span>
</div>
</nav>5.3 圣杯布局
圣杯布局是一种经典的三栏布局:两边定宽,中间自适应。
.holy-grail {
display: flex;
min-height: 100vh;
}
.holy-grail .header,
.holy-grail .footer {
flex: 0 0 60px; /* 定高60px */
}
.holy-grail .body {
display: flex;
flex: 1; /* 中间主体占据剩余空间 */
}
.holy-grail .sidebar {
flex: 0 0 200px; /* 侧边栏定宽200px */
background: #f5f5f5;
}
.holy-grail .main {
flex: 1; /* 主内容自适应 */
}<div class="holy-grail">
<header class="header">头部</header>
<div class="body">
<aside class="sidebar sidebar-left">左侧栏</aside>
<main class="main">主内容</main>
<aside class="sidebar sidebar-right">右侧栏</aside>
</div>
<footer class="footer">底部</footer>
</div>5.4 卡片网格
使用 Flexbox 可以实现响应式卡片网格布局。
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
/* 每个卡片最小280px,最大平分剩余空间 */
flex: 1 1 280px;
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 如果一行只有一张卡片,让它不要撑满 */
.card:only-child {
flex: 0 1 280px;
max-width: 400px;
}<div class="card-grid">
<div class="card">
<h3>卡片1</h3>
<p>卡片内容...</p>
</div>
<div class="card">
<h3>卡片2</h3>
<p>卡片内容...</p>
</div>
<div class="card">
<h3>卡片3</h3>
<p>卡片内容...</p>
</div>
</div>6. 常见问题与解决方案
6.1 项目不换行被压缩
问题:容器设置 display: flex 后,子元素被压缩成一条线。
原因:flex-wrap: nowrap(默认值)导致所有项目在一条线上。
解决方案:
.container {
display: flex;
flex-wrap: wrap; /* 允许换行 */
}6.2 项目没有填满容器高度
问题:容器有高度,但项目没有填满。
原因:项目的 align-items 默认值是 stretch,但如果项目设置了固定高度或内容高度,默认为 auto。
解决方案:
.container {
display: flex;
height: 100vh;
align-items: stretch; /* 默认值,使项目填满容器 */
}
/* 如果想让某个项目不拉伸 */
.item {
align-self: flex-start;
}6.3 justify-content 和 align-items 混淆
问题:不确定哪个属性控制哪个方向。
记忆技巧:
justify-谐音" justice "(正义/公正),处理主轴(main axis)上的分布align-处理交叉轴(cross axis)上的对齐
.container {
flex-direction: row; /* 主轴是水平的 */
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}6.4 项目之间的间距问题
问题:使用 margin 设置项目间距时,space-between 等对齐方式效果不对。
原因:margin 会影响 Flexbox 的空间分配计算。
解决方案:使用 gap 属性代替 margin:
.container {
display: flex;
gap: 20px; /* 项目间距20px */
}
.item {
margin: 0; /* 移除项目的margin */
}6.5 flex-basis、width、min-width 冲突
问题:同时设置 flex-basis、width 和 min-width 时,不确定哪个生效。
规则(按优先级从高到低):
max-width/min-widthflex-basis(当flex-direction为row时,类似于width)width(仅当flex-basis为auto时生效)
.item {
flex-basis: 200px; /* 基础尺寸 */
width: 300px; /* 被忽略,因为 flex-basis 不是 auto */
min-width: 100px; /* 最小宽度优先 */
}6.6 flex-grow 不生效
问题:设置了 flex-grow,但项目没有放大。
检查点:
- 容器是否有剩余空间?
flex-grow只在有剩余空间时生效 - 项目是否设置了
flex-shrink: 0导致无法释放空间? - 项目是否设置了固定宽度?
.container {
display: flex;
width: 100%; /* 确保容器有明确尺寸 */
}
.item {
flex-grow: 1;
flex-basis: 0; /* 重要:设置为0可以让 flex-grow 从0开始计算 */
}6.7 子元素不是预期方向
问题:项目没有按预期的方向排列。
检查:
flex-direction的方向是否正确- 如果是
row-reverse或column-reverse,顺序是从终点开始排布
.container {
flex-direction: row; /* 确认主轴方向 */
}6.8 滚动区域内 Flexbox 失效
问题:在 overflow: auto 的容器中使用 Flexbox,但滚动不生效。
解决方案:确保 Flex 容器的高度计算正确:
.scroll-container {
height: 300px;
overflow: auto;
}
.scroll-container .flex-wrapper {
display: flex;
flex-direction: column; /* 或其他需要的方向 */
}附录:Flexbox 速查表
容器属性速查
| 属性 | 值 | 说明 |
|---|---|---|
display | flex / inline-flex | 定义弹性容器 |
flex-direction | row / column / row-reverse / column-reverse | 主轴方向 |
flex-wrap | nowrap / wrap / wrap-reverse | 是否换行 |
justify-content | flex-start / center / flex-end / space-between / space-around / space-evenly | 主轴对齐 |
align-items | stretch / flex-start / flex-end / center / baseline | 交叉轴对齐 |
align-content | stretch / flex-start / flex-end / center / space-between / space-around | 多行对齐 |
gap | <length> / <percentage> | 间距 |
项目属性速查
| 属性 | 值 | 说明 |
|---|---|---|
flex-grow | <number>(默认 0) | 放大比例 |
flex-shrink | <number>(默认 1) | 缩小比例 |
flex-basis | <length> / auto(默认 auto) | 基础尺寸 |
flex | initial / none / auto / <number> | 简写 |
align-self | auto / stretch / flex-start / flex-end / center / baseline | 单独对齐 |
order | <integer>(默认 0) | 排列顺序 |
