序:一个布局工具,改变了整个前端

2012 年,CSS Flexible Box Layout(简称 Flexbox)被 W3C 正式提出。彼时,前端开发者还在用 floatinline-blocktable 甚至负 margin 来实现页面布局——垂直居中要写三行 hack,等分布局要算百分比算到头疼。

Flexbox 的出现,彻底终结了这种痛苦。

今天,Flex 布局已经是前端开发的基础功,不夸张地说:不会 Flex,就不是合格的前端开发者

这篇文章将带你从概念到实战,系统掌握 Flex 布局的全部核心知识。


一、为什么要学 Flex?先看一个对比

在 Flex 出现之前,实现一个水平等分三列、垂直居中的导航栏,大概是这样的:

1
2
3
4
5
6
7
8
9
10
11
/* 传统方案:float + inline-block 大乱斗 */
.nav {
text-align: center;
line-height: 60px; /* 垂直居中靠行高硬凑 */
}
.nav-item {
display: inline-block;
width: 33.33%; /* 等分靠手算小数 */
float: left; /* 浮动带来的清除问题 */
}
/* 还要写 clearfix…… */

而用 Flex:

1
2
3
4
5
6
.nav {
display: flex;
justify-content: space-around;
align-items: center;
height: 60px;
}

四行代码,干净利落。这就是 Flex 的威力。


二、核心概念:容器与项目

Flex 布局的设计哲学很清晰——一切围绕两根轴线展开

两个角色,各司其职

角色 英文 职责
Flex 容器 Flex Container 定义布局规则,控制子元素的排列方向、对齐方式
Flex 项目 Flex Items 容器内的直接子元素,按容器的规则参与布局
1
2
3
4
5
<div class="container">          <!-- 容器 -->
<div class="item">A</div> <!-- 项目 -->
<div class="item">B</div> <!-- 项目 -->
<div class="item">C</div> <!-- 项目 -->
</div>
1
2
3
.container {
display: flex; /* 激活! */
}

就这一行 display: flex,容器变成了 Flex 容器,子元素自动排成一行。没有浮动,没有清除,没有 hack。

两根轴:理解 Flex 的灵魂

Flex 布局最核心的抽象,是主轴(Main Axis)交叉轴(Cross Axis)

1
2
3
4
       主轴方向 (默认 →)
┌──────┬──────┬──────┐
│ A │ B │ C │ ← 交叉轴方向 (默认 ↓)
└──────┴──────┴──────┘
  • 主轴:项目排列的主要方向(默认水平从左到右)
  • 交叉轴:垂直于主轴的方向(默认垂直从上到下)

记住这个口诀:所有对齐属性,要么控制主轴方向的排列,要么控制交叉轴方向的排列。 理解了这一点,Flex 就理解了 80%。


三、容器属性详解(6 个核心属性)

容器是 Flex 布局的”总控台”。所有容器属性都以 display: flex 为前提。

3.1 flex-direction:决定主轴方向

主轴方向决定了项目是横着排还是竖着排。

1
2
3
4
.container {
display: flex;
flex-direction: row | row-reverse | column | column-reverse;
}
主轴方向 效果
row(默认) 水平 → 项目从左到右排列
row-reverse 水平 ← 项目从右到左排列
column 垂直 ↓ 项目从上到下排列
column-reverse 垂直 ↑ 项目从下到上排列

常见使用场景:移动端布局通常用 column 让内容纵向堆叠。

3.2 justify-content:控制主轴对齐

当容器有剩余空间时,项目在主轴上如何分布?

1
2
3
.container {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
效果 典型场景
flex-start(默认) 靠主轴起点排列 普通列表
flex-end 靠主轴终点排列 右对齐按钮组
center 居中排列 居中导航栏
space-between 两端对齐,项目间等距 两端对齐的菜单
space-around 每个项目两侧间距相等 松散分布的卡片
space-evenly 所有间距完全相等 等间距标签组

3.3 align-items:控制交叉轴对齐(单行)

1
2
3
.container {
align-items: stretch | flex-start | flex-end | center | baseline;
}
效果 典型场景
stretch(默认) 拉伸填满容器高度 等高列布局
flex-start 顶部对齐 卡片顶部对齐
flex-end 底部对齐 底部按钮组
center 垂直居中 最常用的垂直居中方案
baseline 文字基线对齐 不同字号的文字对齐

align-items: center 配合容器固定高度,是最简单可靠的垂直居中方案。

3.4 flex-wrap:控制是否换行

1
2
3
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
效果
nowrap(默认) 不换行,项目会压缩
wrap 空间不够时换行
wrap-reverse 反向换行(从下往上堆叠)

3.5 align-content:多行时的交叉轴分布

flex-wrap: wrap 且有多个行时,控制行与行之间在交叉轴上的分布方式。

1
2
3
.container {
align-content: stretch | flex-start | flex-end | center | space-between | space-around;
}

注意区分align-items 控制单行内项目的对齐;align-content 控制多行之间的分布。单行时 align-content 无效。

3.6 gap:项目之间的间距

这是现代浏览器都支持的好东西,替代了传统的 margin hack。

1
2
3
4
5
6
.container {
gap: 16px; /* 行间距 = 列间距 = 16px */
gap: 20px 12px; /* 行间距 20px,列间距 12px */
row-gap: 20px; /* 仅行间距 */
column-gap: 12px; /* 仅列间距 */
}

四、项目属性详解(6 个核心属性)

容器的规则是”通用规则”,项目属性则是对特定项目的”个性化配置”。

4.1 flex-grow:分配剩余空间

定义项目在容器有剩余空间时的”贪吃能力”。默认值为 0,表示不放大。

1
2
3
.item-1 { flex-grow: 1; }  /* 分 1 份 */
.item-2 { flex-grow: 2; } /* 分 2 份 */
.item-3 { flex-grow: 1; } /* 分 1 份 */

如果容器剩余 400px,按 1:2:1 分配,三个项目分别获得 100px、200px、100px。

4.2 flex-shrink:空间不足时的收缩

当容器空间不足时,控制项目的收缩比例。默认值为 1

1
2
3
.item-fixed {
flex-shrink: 0; /* 打死也不缩 */
}

经典场景:侧边栏固定宽度,主区域自适应:

1
2
.sidebar  { width: 260px; flex-shrink: 0; }
.main { flex: 1; }

4.3 flex-basis:项目的初始尺寸

在分配剩余空间之前,项目占据的主轴空间。默认值为 auto(以项目自身尺寸为准)。

1
2
3
.item {
flex-basis: 200px; /* 初始宽度 200px */
}

4.4 flex:三合一简写(最常用)

这是你写得最多的属性:

1
2
3
4
.item {
flex: flex-grow flex-shrink flex-basis;
/* 等价于分别写三个属性 */
}
简写 展开 含义
flex: 1 flex: 1 1 0% 均分剩余空间,可缩可放
flex: auto flex: 1 1 auto 基于内容尺寸均分
flex: none flex: 0 0 auto 固定尺寸,不伸缩
flex: 0 0 200px flex: 0 0 200px 固定 200px宽

90% 的场景,你只需要记住 flex: 1(自适应均分)和 flex: 0 0 200px(固定宽度)。

4.5 align-self:单个项目的交叉轴对齐

可以覆盖容器的 align-items,让某个项目”开小差”。

1
2
.container { align-items: center; }
.special-item { align-self: flex-end; } /* 只有它底部对齐 */

4.6 order:调整项目排列顺序

默认所有项目 order: 0。数字越小越靠前。

1
2
3
.item-1 { order: 3; }  /* 跑到最后 */
.item-2 { order: 1; } /* 排第一 */
.item-3 { order: 2; } /* 排第二 */

注意order 只影响视觉顺序,不影响 DOM 结构和屏幕阅读器的阅读顺序。


五、实战案例(三个高频场景)

案例一:经典三栏布局

1
2
3
4
5
<div class="layout">
<aside class="sidebar">侧边栏</aside>
<main class="content">主内容区</main>
<aside class="sidebar-right">右侧栏</aside>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.layout {
display: flex;
min-height: 100vh;
}

.sidebar {
width: 240px;
flex-shrink: 0; /* 固定 240px,不缩小 */
background: #f5f5f5;
}

.content {
flex: 1; /* 占据所有剩余空间 */
padding: 24px;
}

.sidebar-right {
width: 300px;
flex-shrink: 0;
background: #fafafa;
}

案例二:响应式卡片网格

1
2
3
4
5
6
7
<div class="card-grid">
<div class="card">卡片 1</div>
<div class="card">卡片 2</div>
<div class="card">卡片 3</div>
<div class="card">卡片 4</div>
<div class="card">卡片 5</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}

.card {
flex: 0 0 calc(33.333% - 14px); /* 每行 3 个,减去 gap 的影响 */
min-width: 280px; /* 小屏幕时自动换行 */
padding: 20px;
border-radius: 8px;
background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}

/* 移动端:一列 */
@media (max-width: 768px) {
.card {
flex: 0 0 100%;
}
}

案例三:垂直居中(最简单也最常用)

1
2
3
4
5
6
.center-box {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 100vh;
}

就四行 CSS,搞定一个在 Flex 出现之前让无数前端程序员头疼的垂直居中问题。


六、常见陷阱与最佳实践

6.1 陷阱一:直接子元素才是 Flex 项目

1
2
3
4
5
6
<div style="display: flex">
<div>我是 Flex 项目 ✓</div>
<span>
<p>我不是 Flex 项目 ✗</p> <!-- 嵌套太深,不受 Flex 影响 -->
</span>
</div>

Flex 布局只影响直接子元素。嵌套元素需要用传统方式处理,或者再开一个 Flex 容器。

6.2 陷阱二:flex: 1flex-grow: 1 不一样

1
2
.a { flex: 1; }        /* 等价于 flex: 1 1 0% */
.b { flex-grow: 1; } /* 等价于 flex: 0 1 auto(注意 flex-basis 是 auto!) */
  • flex: 1:从 0 开始分配,所有项目分到的空间完全按比例
  • flex-grow: 1:从内容宽度开始分配,内容大小会影响最终结果

建议:永远用 flex 简写,行为更可预测。

6.3 陷阱三:align-content 在单行时无效

1
2
3
4
5
/* 单行 flex 容器 */
.container {
display: flex;
align-content: center; /* 无效!因为只有一行 */
}

align-content 只在 flex-wrap: wrap 且有多个行时才生效。单行时,用 align-items

6.4 陷阱四:滚动区域需要 min-height: 0

1
2
3
4
5
.scroll-area {
flex: 1;
overflow-y: auto;
min-height: 0; /* 必须加!否则内容撑破容器 */
}

Flex 项目默认 min-height: auto,这意味着项目的隐式最小高度等于内容高度。当内容溢出时,项目会被撑大而不是出现滚动条。加 min-height: 0(或 min-width: 0)解决这个问题。

6.5 最佳实践速查表

需求 代码
水平居中 justify-content: center
垂直居中 align-items: center(单行)
两端对齐 justify-content: space-between
均分宽度 每个项目 flex: 1
固定侧边栏 width: 260px; flex-shrink: 0
换行卡片 flex-wrap: wrap; gap: 16px
底部固定 margin-top: auto(单个项目推到底部)
排列方向 flex-direction: column

七、总结

Flex 布局的学习曲线其实很平缓——核心就这么几个概念,关键是多练。

一个记忆框架

  1. 容器调 display: flex
  2. 主轴方向定 flex-direction(默认 row,够了)
  3. 主轴对齐用 justify-content
  4. 交叉轴对齐用 align-items
  5. 项目伸缩用 flex 简写
  6. 间距用 gap

掌握了这六步,你就能应对 90% 的布局场景。剩下的 10%,Grid 布局在等着你。


延伸阅读


本文写于 2026 年 6 月 26 日,使用 Chrome 的最新 Flexbox 实现作为参考。所有代码示例均经过验证。