Flex 布局
Category(分类): CSS Status: 已整理
Flex(Flexible Box Layout,弹性盒布局)是一种一维布局模型,主要用于安排一行或一列中的项目。它可以根据容器剩余空间放大或缩小项目,也可以在项目较多时换行。
Flex 适合处理:
- 导航栏和工具栏;
- 水平或垂直居中;
- 等分布局;
- 两端对齐;
- 卡片列表和响应式换行;
- 项目尺寸不固定的布局。
一、Flex 基本概念
Flex 容器中主要有两条轴:
- 主轴(main axis):项目排列的方向;
- 交叉轴(cross axis):与主轴垂直的方向。
容器中的直接子元素称为 Flex item。项目在主轴上占据的尺寸称为 main size,在交叉轴上占据的尺寸称为 cross size。
不能简单地把宽度理解成 main size、高度理解成 cross size。默认 flex-direction: row 时,主轴通常是水平方向;如果设置为 column,主轴就变成垂直方向。
此外,row 和 column 依据当前书写模式决定方向。在默认的水平、从左到右书写模式中,row 通常从左向右排列;在 RTL 或垂直书写模式中,起点和方向可能不同。

二、Flex 容器属性
1. 创建 Flex 容器
任何元素都可以设置为 Flex 容器:
.container {
display: flex;
}
.inline-container {
display: inline-flex;
}
flex:容器本身表现为块级盒子;inline-flex:容器本身表现为行内级盒子;- 两者的直接子元素都会按照 Flex 规则布局。
Flex 容器的直接子元素会成为 Flex item。Flex item 上的 float、clear 和 vertical-align 不参与 Flex 布局,但这些属性并不会因此在整个文档中失效。
三、flex-direction:主轴方向
.container {
flex-direction: row;
}
可选值:
row | row-reverse | column | column-reverse
默认值是 row。
1. row
沿当前书写模式的行向轴排列。在默认水平从左到右的页面中,通常表现为从左到右:
.container {
display: flex;
flex-direction: row;
}

2. row-reverse
反转主轴的起点。在默认从左到右的页面中,通常表现为从右到左:
.container {
display: flex;
flex-direction: row-reverse;
}

3. column
沿块向轴排列,默认水平书写模式下通常表现为从上到下:
.container {
display: flex;
flex-direction: column;
}

4. column-reverse
反转块向轴的起点,默认水平书写模式下通常表现为从下到上:
.container {
display: flex;
flex-direction: column-reverse;
}

row-reverse 和 column-reverse 只改变视觉排列方向,不会改变 DOM 顺序。涉及键盘操作、屏幕阅读器或有序内容时,不建议仅依赖反向排列表达语义顺序。
四、flex-wrap:项目是否换行
.container {
flex-wrap: nowrap;
}
可选值:
nowrap | wrap | wrap-reverse
默认值是 nowrap。
1. nowrap
所有项目尽量放在同一条 Flex line 中。空间不足时,项目可能根据 flex-shrink 缩小,也可能因为最小尺寸限制而溢出:
.container {
display: flex;
flex-wrap: nowrap;
}
因此不能简单地说 nowrap 一定会让项目自动缩小。是否缩小还取决于 flex-shrink、min-width、min-height 和项目内容。

2. wrap
主轴空间不足时创建新的 Flex line:
.container {
display: flex;
flex-wrap: wrap;
}
在默认水平书写模式下,新的行通常从上到下生成。

3. wrap-reverse
允许换行,并反转交叉轴方向:
.container {
display: flex;
flex-wrap: wrap-reverse;
}
在默认水平书写模式下,新的行通常从下到上生成。

wrap 并不意味着 flex-shrink 永远不会生效。每一条 Flex line 都会独立分配空间;如果某一行仍然存在负剩余空间,项目仍可能缩小。
五、flex-flow:方向和换行的简写
flex-flow 是 flex-direction 和 flex-wrap 的简写:
.container {
flex-flow: row wrap;
}
等价于:
.container {
flex-direction: row;
flex-wrap: wrap;
}
默认值为:
row nowrap
当需要同时设置方向和换行时,使用 flex-flow 可以让代码更紧凑;是否使用它取决于团队的可读性偏好。
六、justify-content:主轴对齐
justify-content 定义项目在主轴上的分布方式:
.container {
justify-content: flex-start;
}
常见取值包括:
flex-start | flex-end | center
space-between | space-around | space-evenly
start | end
默认值为 flex-start。
以下示例假设主轴为水平方向:
1. flex-start
项目靠主轴起点排列:
.container {
display: flex;
justify-content: flex-start;
}

2. flex-end
项目靠主轴终点排列:

3. center
项目在主轴方向居中:

4. space-between
两端项目分别贴近容器起点和终点,项目之间的剩余空间相等:

5. space-around
每个项目两侧的外部间隔相等,因此相邻项目之间的间隔通常是边缘间隔的两倍:

6. space-evenly
项目之间以及项目与容器边缘之间的间隔都相等:
.container {
justify-content: space-evenly;
}
justify-content 分配的是主轴剩余空间。如果项目设置了自动外边距,例如 margin-left: auto,自动外边距会优先消耗剩余空间。
七、align-items:交叉轴上的项目对齐
align-items 定义同一条 Flex line 中项目在交叉轴上的对齐方式:
.container {
align-items: stretch;
}
常见取值包括:
normal | stretch | flex-start | flex-end
center | baseline | start | end
默认值为 stretch。
以下示例假设主轴为水平方向,因此交叉轴是垂直方向。
1. stretch
当容器交叉轴尺寸确定,项目的交叉轴尺寸为 auto,且没有被最小/最大尺寸限制时,项目会拉伸以填充所在 Flex line 的交叉轴尺寸:
.container {
display: flex;
height: 100px;
align-items: stretch;
}
.item {
/* 不设置 height,或设置为 auto */
}
它不一定会让项目无条件占满整个容器高度;多行 Flex 布局还要考虑每一条 Flex line 的尺寸。

2. flex-start
项目靠交叉轴起点对齐:

3. flex-end
项目靠交叉轴终点对齐:

4. center
项目在交叉轴方向居中:

5. baseline
项目按照基线对齐,常用于文字或带文本的控件:
.container {
display: flex;
align-items: baseline;
}
基线不等于元素底边。不同字体、图片、输入框和没有文本基线的项目可能使用不同的基线替代规则。

八、align-content:多条 Flex line 的交叉轴分布
align-content 用于设置多条 Flex line 在交叉轴上的分布方式:
.container {
align-content: stretch;
}
常见取值包括:
normal | stretch | flex-start | flex-end | center
space-between | space-around | space-evenly
start | end
默认值为 normal,在 Flex 布局中通常表现为 stretch。
只有在以下情况下才容易观察到它的效果:
- 容器允许换行;
- 实际产生了两条或更多 Flex line;
- 交叉轴尺寸明确;
- Flex lines 之间存在剩余空间。
例如:
.container {
display: flex;
flex-wrap: wrap;
align-content: space-between;
height: 300px;
}
这里对齐的是多条 Flex line,不是项目本身。align-items 负责一条 Flex line 内项目的对齐,align-content 负责多条 Flex line 之间的分布。

当项目设置了固定高度时,align-content: stretch 主要改变 Flex line 的分布;项目未设置交叉轴尺寸时,还可能受到 align-items: stretch 的影响。

其他常见取值:
.container {
align-content: flex-start;
}

.container {
align-content: flex-end;
}

.container {
align-content: center;
}

.container {
align-content: space-between;
}

.container {
align-content: space-around;
}

九、gap:项目和 Flex line 之间的间距
现代浏览器支持在 Flex 容器中使用 gap:
.container {
display: flex;
flex-wrap: wrap;
gap: 16px 24px;
}
第一个值是行间距,第二个值是列间距。也可以分别使用:
.container {
row-gap: 16px;
column-gap: 24px;
}
gap 只设置项目之间的间距,不会自动产生容器外侧的留白。与给每个项目设置外边距相比,gap 不需要额外处理首尾项目的边距。
十、Flex 项目属性
Flex item 常用的属性包括:
orderflex-basisflex-growflex-shrinkflexalign-self
1. order:视觉排列顺序
.item {
order: 0;
}
order 默认值为 0。数值越小,视觉排列越靠前;数值相同时,按照源文档顺序排列。
.item--first {
order: -1;
}
.item--last {
order: 1;
}

order 不会改变 DOM 顺序、键盘导航顺序和屏幕阅读器阅读顺序。语义顺序应优先通过 HTML 结构表达。
2. flex-basis:Flex 基础尺寸
.item {
flex-basis: 200px;
}
flex-basis 定义项目在分配主轴剩余空间之前的基础尺寸。它沿主轴生效:
- 主轴为 row 时,通常对应宽度方向;
- 主轴为 column 时,通常对应高度方向。
常见取值:
auto | content | <length> | <percentage>
auto 会参考项目的主轴尺寸属性,例如 row 方向下的 width;如果主轴尺寸也是 auto,则可能根据内容计算。
.item {
flex-basis: 200px;
width: 400px;
}
当 flex-basis 不是 auto 时,它通常优先于主轴尺寸属性,但 min-* 和 max-* 仍可能限制最终尺寸。
flex-basis: 0 或 0% 常用于让项目从零基础尺寸开始分配剩余空间,但最终尺寸仍可能受 min-width: auto、内容最小尺寸和最小/最大尺寸限制。
3. flex-grow:放大比例
.item {
flex-grow: 0;
}
默认值为 0,表示有剩余空间时项目不会主动放大。
当一条 Flex line 的项目基础尺寸之和小于容器主轴尺寸时,会产生正剩余空间。flex-grow 大于 0 的项目可以按比例分配这部分空间:
.item {
flex-grow: 1;
}
.item--large {
flex-grow: 2;
}
如果项目的 flex-grow 都是 1,通常会均分剩余空间;如果一个项目为 2、其他项目为 1,它通常分得两倍的剩余空间。
实际分配还会受到 min-width、max-width、min-height、max-height 等约束影响,并且多行 Flex 会按行分别计算。

4. flex-shrink:收缩比例
.item {
flex-shrink: 1;
}
默认值为 1。当一条 Flex line 的基础尺寸之和超过容器主轴尺寸时,项目可能缩小。负数对 flex-shrink 无效。
.item--fixed {
flex-shrink: 0;
}
flex-shrink 并不是简单地让所有项目同比例缩小。实际负空间通常按照以下因素加权分配:
flex-shrink × flex base size
项目基础尺寸越大,即使 flex-shrink 值相同,也可能承担更多缩小量。同时,自动最小尺寸和 min-width 可能阻止项目继续缩小。

5. flex:三个属性的简写
flex 是以下三个属性的简写:
.item {
flex: <flex-grow> <flex-shrink> <flex-basis>;
}
常见写法:
.item {
flex: 1 1 200px;
}
等价于:
.item {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 200px;
}
flex 的默认值是:
.item {
flex: 0 1 auto;
}
常用快捷值:
| 写法 | 常见等价形式 | 含义 |
|---|---|---|
flex: 1 | 1 1 0% | 从相同的基础尺寸开始分配空间,常用于等分 |
flex: auto | 1 1 auto | 参考项目原始尺寸并允许伸缩 |
flex: none | 0 0 auto | 不放大、不缩小,保留原始尺寸 |
flex: 0 1 auto | 默认值 | 不放大,空间不足时允许缩小 |
下面是几个常见展开形式:
/* 一个非负数字 */
.item-a {
flex: 1;
/* 常见计算结果:1 1 0% */
}
/* 两个非负数字 */
.item-b {
flex: 2 3;
/* 2 3 0% */
}
/* 一个数字和一个长度 */
.item-c {
flex: 2 32px;
/* 2 1 32px */
}
实际项目中建议使用 flex 简写表达完整意图,而不是随意混用 width、flex-basis 和三个独立的 Flex 属性。
十一、flex-grow、flex-shrink 与换行的关系
可以按每条 Flex line 的空间情况理解:
flex-wrap: nowrap且基础尺寸之和小于容器尺寸时,存在正剩余空间,flex-grow可能生效;flex-wrap: nowrap且基础尺寸之和大于容器尺寸时,存在负剩余空间,flex-shrink可能生效;flex-wrap: wrap时,项目会先根据换行规则形成多条 Flex line;每一行再单独计算剩余空间;- 某一行有正剩余空间时,该行的
flex-grow可能生效; - 某一行有负剩余空间时,该行的
flex-shrink仍可能生效; flex-grow和flex-shrink通常不会在同一次空间分配中同时作为主要方向生效,但换行后的不同 Flex line 可以分别出现不同情况。
示例:
.container {
display: flex;
flex-wrap: wrap;
width: 320px;
}
.item {
flex: 1 1 180px;
min-width: 0;
}
这里每一行都可能根据实际项目数量产生放大或缩小。不能简单认为 wrap 后空间永远足够。
十二、align-self:单独设置项目对齐方式
align-self 可以覆盖单个项目的 align-items 设置:
.container {
display: flex;
align-items: flex-start;
}
.item--center {
align-self: center;
}
常见取值包括:
auto | normal | stretch | flex-start | flex-end
center | baseline | start | end
默认值为 auto。它会使用父 Flex 容器的 align-items 计算结果;这不是普通 CSS 意义上的属性继承。
align-items 作用于容器中的项目,align-self 只作用于当前项目:

十三、常见问题和实用技巧
1. 文本或长单词导致 Flex 项目无法缩小
Flex item 默认的自动最小尺寸可能来自内容的最小尺寸。长文本、长 URL 或不可换行内容可能导致项目溢出:
.item {
min-width: 0;
overflow-wrap: anywhere;
}
对于垂直 Flex 容器中的滚动区域,通常还需要:
.column-container {
display: flex;
flex-direction: column;
min-height: 0;
}
2. 使用 margin: auto 推开项目
.header {
display: flex;
align-items: center;
}
.header__actions {
margin-left: auto;
}
在主轴方向上,自动外边距会优先吸收剩余空间,常用于把操作按钮推到右侧。
3. 项目垂直居中
.container {
display: flex;
align-items: center;
justify-content: center;
}
justify-content 控制主轴,align-items 控制交叉轴。改变 flex-direction 后,两者所对应的物理方向也会改变。
4. gap 和外边距的选择
优先使用 gap 表示项目之间的间距:
.list {
display: flex;
gap: 16px;
}
只有需要让某个项目自动占据剩余空间,或需要与外部布局交互时,才使用 margin: auto 或普通外边距。
5. 注意视觉顺序和语义顺序
如果页面内容有明确的阅读顺序,应优先调整 HTML 结构,不要依赖 order 或 row-reverse 代替语义结构。
十四、Flex 布局与其他布局方式
Flex 是一维布局,适合处理单行或单列中的项目分布。Grid 是二维布局,更适合同时控制行和列。
- 一行导航栏:优先考虑 Flex;
- 多行多列且行列需要同时对齐:优先考虑 Grid;
- 简单的项目间距:优先使用
gap; - 复杂图形或精确路径:考虑 SVG;
- 内容语义顺序:优先由 HTML 结构保证。
总结
Flex 布局的核心不是记住几个对齐属性,而是理解以下关系:
flex-direction决定主轴方向;flex-wrap决定是否生成多条 Flex line;justify-content控制主轴上的剩余空间分布;align-items控制一条 Flex line 内项目的交叉轴对齐;align-content控制多条 Flex line 的交叉轴分布;flex-basis确定项目的基础尺寸;flex-grow分配正剩余空间;flex-shrink分配负剩余空间;align-self覆盖单个项目的交叉轴对齐;order只改变视觉顺序,不改变 DOM 和无障碍阅读顺序。
实际开发中,应结合项目的书写模式、最小尺寸、内容长度、换行策略和可访问性进行判断,而不要把 Flex 属性简单理解成只针对水平布局的固定规则。