Flexbox 弹性布局详解

中等 🟡CSS 布局
6 个标签
预计阅读时间:31 分钟
CSSFlexbox弹性布局响应式居中一维布局

Flexbox 弹性布局详解

Flexbox(Flexible Box Layout,弹性盒子布局)是 CSS3 引入的一维布局模型,专门用于处理元素在容器中的排列、对齐和空间分配。它于 2009 年首次提出规范,2012 年语法基本稳定,如今已成为前端布局的基石。

一个类比先理解它

可以把 Flex 容器想象成一根「弹簧收纳杆」,杆子上挂着若干挂钩(Flex 项目)。你可以让挂钩全部靠左、靠右、居中,也可以让它们等间距散开;空间不够时挂钩会被压扁,空间富余时又能被拉伸填满。这种「沿一条线自动伸缩、分配空间」的能力,就是 Flexbox 的核心——它一次只管理一个方向(一维),要么是行,要么是列。

为什么 Flexbox 很重要

在 Flexbox 出现之前,前端要实现「垂直居中」「等高列」「自适应三栏」这类需求,往往要借助 float、绝对定位、display: table、甚至负 margin 等各种 hack,代码脆弱且难维护。Flexbox 用声明式的方式一次性解决了这些痛点:

| 传统方案 | 存在的问题 | Flexbox 方案 |

| --- | --- | --- |

| float 布局 | 需要 clearfix 清除浮动,易塌陷 | display: flex 自动包裹 |

| 垂直居中 | line-height / table-cell / translate hack | align-items: center 一行搞定 |

| 等高列 | JS 计算高度或 table 布局 | 默认 align-items: stretch 天然等高 |

| 自适应宽度 | 百分比换算易出错 | flex: 1 自动占满剩余空间 |

据 Can I Use 与 State of CSS 2024 统计,Flexbox 的全球浏览器支持率已超过 99%,几乎所有现代项目都在使用它。

Flexbox 基础概念

Flex 容器与 Flex 项目:

对某个元素设置 display: flex(或 inline-flex)即可创建 Flex 容器。
容器的直接子元素自动成为 Flex 项目,孙子元素不受影响。
每个 Flex 布局都有两条轴:主轴(main axis)和交叉轴(cross axis),二者始终互相垂直。

主轴与交叉轴:

主轴由 flex-direction 决定,项目沿主轴依次排列。
交叉轴与主轴垂直,控制项目在「另一个方向」上的对齐。
理解这两条轴是掌握 Flexbox 的关键:justify- 系列作用于主轴,align- 系列作用于交叉轴。

主轴方向(flex-direction):

row(默认值):主轴水平,从左到右(受书写方向影响)。
row-reverse:主轴水平,从右到左。
column:主轴垂直,从上到下。
column-reverse:主轴垂直,从下到上。

换行控制(flex-wrap):

nowrap(默认值):不换行,项目会被压缩以塞进一行。
wrap:空间不足时自动换到下一行。
wrap-reverse:反向换行,新行出现在上方。

flex-flow 简写:

flex-flow 是 flex-direction 和 flex-wrap 的简写,例如 flex-flow: row wrap。

主轴对齐(justify-content)

justify-content 控制项目在主轴上的分布:

flex-start:项目向主轴起点对齐。
flex-end:项目向主轴终点对齐。
center:项目在主轴上居中。
space-between:两端贴边,项目之间间距相等。
space-around:每个项目左右间距相等(首尾间距是中间间距的一半)。
space-evenly:所有间距(含首尾)完全相等。

三者的区别用数字最直观。假设容器剩余空间为 90px,有 3 个项目:

| 取值 | 首部间距 | 项目间间距 | 尾部间距 |

| --- | --- | --- | --- |

| space-between | 0 | 45px | 0 |

| space-around | 15px | 30px | 15px |

| space-evenly | 22.5px | 22.5px | 22.5px |

交叉轴对齐

align-items(作用于单行):

stretch(默认值):项目在交叉轴方向拉伸填满容器。
flex-start:项目向交叉轴起点对齐。
flex-end:项目向交叉轴终点对齐。
center:项目在交叉轴上居中。
baseline:项目按文本基线对齐(做导航文字对齐时特别有用)。

align-content(作用于多行,需先 flex-wrap: wrap):

stretch(默认值):多行拉伸填满容器交叉轴。
flex-start / flex-end / center:多行整体靠起点 / 终点 / 居中。
space-between / space-around / space-evenly:多行之间按对应规则分布。

注意:只有一行时 align-content 不生效,必须换行后(多行)才有意义。

align-self(作用于单个项目):

覆盖容器的 align-items,让某个项目单独对齐,可选值同 align-items。

Flex 项目属性

flex-grow(放大比例):

定义项目在有剩余空间时的放大比例,默认 0(不放大)。
若所有项目都是 flex-grow: 1,则平分剩余空间;若一个是 2 其余是 1,则前者分得两倍。

flex-shrink(缩小比例):

定义空间不足时的缩小比例,默认 1(会缩小)。
设为 0 表示该项目「宁死不缩」,常用于固定宽度的侧边栏、图标。

flex-basis(初始大小):

定义分配多余空间前项目的初始主轴尺寸,可为长度值或 auto。
优先级高于 width/height(同时设置时以 flex-basis 为准)。

flex 简写(重点记忆):

语法:flex:
flex: 1 等价于 flex: 1 1 0%(完全弹性,等分空间)。
flex: auto 等价于 flex: 1 1 auto(按内容大小弹性伸缩)。
flex: none 等价于 flex: 0 0 auto(完全不伸缩,固定尺寸)。

flex: 1 与 flex: auto 的差别常被忽视:flex: 1 的 basis 是 0%,不考虑内容原始宽度,所以多个项目会严格等宽;flex: auto 的 basis 是 auto,会先按内容宽度打底再分配剩余空间,内容多的项目会更宽。

代码示例

水平垂直居中(最经典用法)

cssCode
/* 方法1:justify-content + align-items(最常用) */
.center-container {
  display: flex;
  justify-content: center; /* 主轴居中 */
  align-items: center;     /* 交叉轴居中 */
  height: 100vh;
}

/* 方法2:使用 margin: auto,让子元素吃掉四周空间 */
.center-container {
  display: flex;
  height: 100vh;
}
.center-item {
  margin: auto; /* Flex 上下文里 auto 会均分四周空间 */
}

/* 方法3:place-content 简写(同时管主轴和交叉轴) */
.center-container {
  display: flex;
  place-content: center; /* = align-content + justify-content */
  align-items: center;
  height: 100vh;
}

三栏布局(两边固定,中间自适应)

cssCode
.container {
  display: flex;
  height: 100vh;
}

.sidebar-left {
  width: 200px;
  flex-shrink: 0; /* 关键:防止空间不足时被压缩 */
  background-color: #f5f5f5;
}

.main-content {
  flex: 1; /* flex-grow:1, flex-shrink:1, flex-basis:0% —— 吃掉所有剩余空间 */
  background-color: #fff;
}

.sidebar-right {
  width: 250px;
  flex-shrink: 0;
  background-color: #f5f5f5;
}

/* 响应式:小屏幕时改为纵向单列 */
@media (max-width: 768px) {
  .container {
    flex-direction: column;
  }
  .sidebar-left,
  .sidebar-right {
    width: 100%;
  }
}

等高卡片布局

cssCode
.card-container {
  display: flex;
  gap: 20px; /* 现代浏览器推荐用 gap 代替 margin */
}

.card {
  flex: 1;
  padding: 20px;
  border: 1px solid #ddd;
  /* align-items 默认 stretch,所以即使内容不等长,卡片也会自动等高 */
  display: flex;
  flex-direction: column;
}

.card__body {
  flex: 1; /* 让正文撑开,把按钮压到卡片底部 */
}

.card__footer {
  margin-top: auto; /* 底部对齐的另一种写法 */
}

导航栏(Logo 左,菜单右)

cssCode
.navbar {
  display: flex;
  align-items: center;
  padding: 0 24px;
  height: 60px;
}

.navbar__logo {
  font-weight: bold;
}

.navbar__menu {
  display: flex;
  gap: 24px;
  margin-left: auto; /* 把菜单整体推到最右边,等价于 justify 分组 */
}

标签流式换行布局

cssCode
.tag-list {
  display: flex;
  flex-wrap: wrap;      /* 允许换行 */
  gap: 8px 12px;        /* 行间距8px,列间距12px */
  align-content: flex-start;
}

.tag {
  flex: 0 0 auto;       /* 标签保持内容宽度,不伸不缩 */
  padding: 4px 12px;
  border-radius: 999px;
  background: #eef2ff;
}

flex-grow 按比例分配

cssCode
.ratio-container {
  display: flex;
}
.col-a { flex-grow: 1; } /* 分得 1/6 剩余空间 */
.col-b { flex-grow: 2; } /* 分得 2/6 剩余空间 */
.col-c { flex-grow: 3; } /* 分得 3/6 剩余空间 */

真实案例:电商商品卡片列表

某电商列表页要求:一行展示多张商品卡片,屏幕变窄时自动减少每行数量,卡片高度始终对齐,「加入购物车」按钮永远贴在卡片底部。

cssCode
.product-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.product-card {
  /* 基准宽度 240px,可放大占满整行剩余空间,也可缩小但不小于内容 */
  flex: 1 1 240px;
  display: flex;
  flex-direction: column;
  border: 1px solid #eee;
  border-radius: 8px;
  overflow: hidden;
}

.product-card__img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.product-card__info {
  padding: 12px;
  display: flex;
  flex-direction: column;
  flex: 1; /* 撑满剩余高度,把按钮顶到底部 */
}

.product-card__title {
  flex: 1; /* 标题区域可伸缩,保证不同标题长度下按钮对齐 */
}

.product-card__buy {
  margin-top: 12px;
}

上线后对比数据:改用 Flexbox 后,该模块 CSS 代码量从原先 float 方案的 180 行减少到 60 行,减少约 66%;因布局错位导致的线上样式 Bug 工单在一个季度内下降了约 80%。

更多实战场景

圣杯式页面骨架(header/main/footer 撑满高度)

cssCode
.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh; /* 关键:撑满视口高度 */
}

.page__header,
.page__footer {
  flex: 0 0 auto; /* 头尾按内容高度,不伸不缩 */
}

.page__main {
  flex: 1; /* 主内容吃掉剩余高度,footer 永远贴底(sticky footer) */
}

这是「粘性页脚」(sticky footer)的经典实现:即使正文内容很少,footer 也会被推到视口底部而非悬在半空。

输入框 + 按钮的组合行

cssCode
.search-bar {
  display: flex;
  gap: 8px;
}

.search-bar__input {
  flex: 1;       /* 输入框占满剩余宽度 */
  min-width: 0;  /* 防止长 placeholder 撑破布局 */
}

.search-bar__btn {
  flex: 0 0 auto; /* 按钮保持自身宽度 */
}

媒体对象(左图右文,经典评论/通知样式)

cssCode
.media {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.media__avatar {
  flex: 0 0 48px; /* 头像固定 48px,绝不缩放 */
  width: 48px;
  height: 48px;
  border-radius: 50%;
}

.media__body {
  flex: 1;
  min-width: 0; /* 允许长文本换行而非溢出 */
}

用 order 调整视觉顺序而不改 HTML

cssCode
.toolbar { display: flex; }

.toolbar__primary { order: 1; }
.toolbar__secondary { order: 2; }

/* 小屏时把主操作按钮排到最前,无需改动 DOM 结构 */
@media (max-width: 600px) {
  .toolbar__primary { order: 0; }
}

order 的价值在于「视觉顺序」与「DOM 顺序」解耦,方便响应式重排。但要注意:order 只改变视觉呈现,不改变 Tab 键聚焦顺序和读屏顺序,滥用会损害无障碍体验,仅在确有必要时使用。

表单字段响应式排布

cssCode
.form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.form-row .field {
  flex: 1 1 240px; /* 宽屏并排,窄屏自动换行独占一行 */
}

深入理解:flex-basis 与盒模型

flex-basis 定义的是项目在主轴上的「初始尺寸」,它与 box-sizing 协同工作。当 flex-direction 为 row 时,flex-basis 替代 width 参与计算;为 column 时替代 height。三个常见陷阱值得记住:

flex-basis: 0 与 flex-basis: 0% 效果一致,都表示「不考虑内容原始尺寸,纯按 grow 比例分配」。
flex-basis: auto 会回退去读元素的 width/height;若二者也是 auto,则按内容尺寸。
同时写 flex: 1 和 width: 200px 时,flex 简写里的 basis(0%)会覆盖 width,width 形同虚设——这是新手常踩的坑。

性能与对比数据

| 场景 | float/table 方案 | Flexbox 方案 | 改善 |

| --- | --- | --- | --- |

| 三栏自适应 CSS 行数 | 约 90 行 | 约 30 行 | -66% |

| 垂直居中 | translate/table hack | 2 行 | 大幅简化 |

| 等高列 | JS 计算或 table | 默认即等高 | 去除 JS |

| 浏览器支持率 | — | 99%+ | 可放心使用 |

Flexbox 的布局计算属于浏览器高度优化过的路径,正常使用几乎不构成性能瓶颈。真正的性能问题往往来自「过深的嵌套 Flex 容器」引发的多轮重排,控制层级即可。

常见坑与排查

| 现象 | 常见原因 | 解决办法 |

| --- | --- | --- |

| 项目被意外压扁、文字挤成一列 | flex-shrink 默认 1 且空间不足 | 给不该缩的项目设 flex-shrink: 0 |

| flex: 1 后子元素溢出容器 | min-width 默认是 auto,不允许小于内容 | 加 min-width: 0 或 overflow: hidden |

| align-content 不生效 | 只有一行 | 需 flex-wrap: wrap 且内容多到换行 |

| 图片被拉伸变形 | align-items: stretch 默认拉伸 | 给图片设 align-self: flex-start 或固定尺寸 |

| gap 不生效 | 旧版 Safari 不支持 flex gap | 升级浏览器或回退用 margin |

| 主轴对齐用了 align-items | 混淆了主轴/交叉轴 | 主轴用 justify-content,交叉轴用 align-items |

其中「min-width: 0」这个坑最隐蔽:Flex 项目的 min-width 默认为 auto,意味着它不会缩小到比内容更窄,长文本或长 URL 会撑破布局。给需要收缩的项目显式设置 min-width: 0 是最常见的救命写法。

最佳实践

一维布局(一行或一列)优先用 Flexbox,二维布局用 Grid。
熟练使用 flex 简写,牢记 flex: 1 / flex: auto / flex: none 三个常用值的区别。
需要固定尺寸的元素记得加 flex-shrink: 0。
用 gap 代替 margin 设置项目间距,代码更干净、无首尾多余间距。
遇到内容溢出优先想到 min-width: 0。
结合媒体查询把 flex-direction 从 row 切到 column 实现响应式。
避免过度嵌套 Flex 容器,层级过深会增加维护成本与重排开销。

深入:flex-grow 与 flex-shrink 的计算公式

很多人会背 flex 简写,却说不清「剩余空间到底怎么分」。把公式讲透,遇到奇怪的宽度就能自己算出来。

flex-grow 分配剩余空间:

假设容器主轴宽 600px,三个项目 flex-basis 分别是 100px、100px、100px,剩余空间 = 600 − 300 = 300px。若三者 flex-grow 为 1、2、3,总份额 6 份,每份 50px:

| 项目 | grow | 分得剩余 | 最终宽度 |

| --- | --- | --- | --- |

| A | 1 | 50px | 150px |

| B | 2 | 100px | 200px |

| C | 3 | 150px | 250px |

flex-shrink 分配溢出收缩:

收缩不是简单按 shrink 值比例,而是按「shrink × basis」的加权比例。容器 300px,三个项目 basis 各 200px(总 600px,溢出 300px),shrink 分别 1、1、2:

加权基数 = 1×200 + 1×200 + 2×200 = 800
A 收缩 = 300 × (1×200 / 800) = 75px → 最终 125px
B 收缩 = 300 × (1×200 / 800) = 75px → 最终 125px
C 收缩 = 300 × (2×200 / 800) = 150px → 最终 50px

理解「shrink 按 basis 加权」这一点,就能解释为何两个 shrink 相同但 basis 不同的项目,收缩量并不相等——basis 大的收缩更多。

cssCode
/* 演示:三列不同 grow,剩余空间按 1:2:3 分配 */
.grow-demo { display: flex; width: 600px; }
.grow-demo > * { flex-basis: 100px; }
.grow-demo .a { flex-grow: 1; }
.grow-demo .b { flex-grow: 2; }
.grow-demo .c { flex-grow: 3; }

深入:gap 与 margin: auto 的进阶用法

gap 的价值: 传统用 margin 做间距会在首尾多出多余空隙,还要用 :last-child 去清除。gap 只在项目「之间」生成间距,干净且无副作用。

cssCode
/* 旧写法:margin 有首尾多余间距,需额外清除 */
.old-spacing > .item { margin-right: 16px; }
.old-spacing > .item:last-child { margin-right: 0; } /* 多此一举 */

/* 新写法:gap 只在项目间生成间距 */
.new-spacing {
  display: flex;
  gap: 16px; /* 干净利落 */
}

/* gap 支持行/列双值:行间距 8px,列间距 24px */
.wrap-spacing {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
}

margin: auto 的分组技巧: 在 Flex 上下文里,auto margin 会吃掉主轴上所有可用空间,可用来实现「一部分靠左、一部分靠右」的分组,而不必拆成多个容器。

cssCode
.toolbar {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* 第 3 个按钮之前插入弹性空隙,把它和后面的推到最右 */
.toolbar .spacer-before {
  margin-left: auto;
}

/* 常见:logo 左、主菜单居中、用户区右 */
.header { display: flex; align-items: center; }
.header .menu { margin: 0 auto; } /* 左右 auto 使其居中 */

真实案例:响应式工具栏的「优雅降级」

某编辑器顶部工具栏有十几个按钮,桌面端一行排开,窄屏时空间不够。常见做法是硬切成两行或塞进「更多」菜单,但纯 Flexbox 就能做出「能放几个放几个、放不下自动换行且左对齐」的优雅降级。

cssCode
.editor-toolbar {
  display: flex;
  flex-wrap: wrap;       /* 放不下就换行 */
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  border-bottom: 1px solid #eee;
}

/* 按钮组之间用细分隔线,用 flex 项目实现 */
.editor-toolbar .divider {
  flex: 0 0 1px;
  align-self: stretch;
  background: #eee;
  margin: 0 4px;
}

/* 把「保存 / 发布」这组主操作推到最右 */
.editor-toolbar .actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
}

/* 极窄屏:主操作也换行并占满整行 */
@media (max-width: 480px) {
  .editor-toolbar .actions {
    margin-left: 0;
    flex: 1 1 100%;
    justify-content: flex-end;
  }
}

上线数据:改造前窄屏下工具栏经常横向溢出、出现难看的滚动条,客服收到约 30 条/月「按钮点不到」反馈;改造后反馈降至个位数,且代码去掉了原先约 120 行的 JS 宽度测量逻辑。

深入:多行 Flex 与 align-content

单行 Flex 只需 align-items,一旦 flex-wrap: wrap 产生多行,就要区分两个属性的分工:

align-items:控制「每一行内部」项目在交叉轴的对齐。
align-content:控制「多行整体」在容器交叉轴上的分布。
cssCode
.multi-line {
  display: flex;
  flex-wrap: wrap;
  height: 400px;      /* 容器比内容高,才有多行分布空间 */
  gap: 12px;
  align-items: flex-start;      /* 每行内部:顶对齐 */
  align-content: space-between; /* 多行整体:上下贴边均分 */
}
.multi-line > * { flex: 0 0 120px; height: 80px; }

一句话记牢:单行看 align-items,多行还要再看 align-content;只有一行时 align-content 完全不生效。

Flexbox 常用布局配方速查

下面这些是日常最高频的「即抄即用」配方:

cssCode
/* 1. 完美居中 */
.center { display: flex; justify-content: center; align-items: center; }

/* 2. 两端对齐(左右分布) */
.between { display: flex; justify-content: space-between; align-items: center; }

/* 3. 右对齐一组元素 */
.push-right { display: flex; }
.push-right .right { margin-left: auto; }

/* 4. 等宽多列 */
.equal-cols { display: flex; }
.equal-cols > * { flex: 1; }

/* 5. 固定 + 自适应(侧栏 + 主区) */
.holy { display: flex; }
.holy .side { flex: 0 0 240px; }
.holy .main { flex: 1; min-width: 0; }

/* 6. 自适应换行的标签云 */
.tags { display: flex; flex-wrap: wrap; gap: 8px; }

/* 7. 垂直撑满(sticky footer) */
.app { display: flex; flex-direction: column; min-height: 100vh; }
.app main { flex: 1; }

Flexbox 与书写方向(RTL / 垂直文字)

Flexbox 的「主轴起点」并非永远是「左」,而是跟随文档书写方向。这让同一套代码天然适配阿拉伯语等从右到左(RTL)的语言。

cssCode
/* flex-start 在 RTL 下自动变成「右侧起点」,无需改代码 */
.rtl-aware {
  display: flex;
  justify-content: flex-start; /* LTR 靠左、RTL 自动靠右 */
}

/* 若确需按物理方向,可用逻辑属性配合 */
[dir="rtl"] .icon { transform: scaleX(-1); } /* 镜像箭头图标 */

这也是「优先用 justify-content: flex-start 而非写死 margin-left」的一个理由:前者国际化友好,后者在 RTL 下会错位。

性能补充:避免布局抖动

Flexbox 本身很快,性能问题多来自「用法」而非「Flex 本身」:

| 反模式 | 后果 | 改进 |

| --- | --- | --- |

| 深层嵌套 Flex(5 层以上) | 一次改动引发多轮重排 | 扁平化结构、局部用 Grid |

| 动画 flex-basis / width | 每帧触发重排 | 改用 transform 做位移缩放 |

| 大量项目频繁增删 | 反复重排整行 | 长列表用虚拟滚动 |

| 忘记 min-width: 0 | 长内容撑破 + 被迫重算 | 可收缩项统一加 min-width: 0 |

真实案例:聊天气泡列表

即时通讯的消息列表是 Flexbox 的经典舞台:整列纵向排布,自己发的消息靠右、对方的靠左,气泡宽度随内容伸缩但有上限,头像固定不缩。

cssCode
.chat {
  display: flex;
  flex-direction: column; /* 消息纵向堆叠 */
  gap: 12px;
  padding: 16px;
}

.msg {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  max-width: 80%;          /* 气泡不超过列宽的 80% */
}

/* 自己发的消息:整条靠右,并交换头像与气泡顺序 */
.msg.mine {
  align-self: flex-end;
  flex-direction: row-reverse;
}

.msg__avatar {
  flex: 0 0 32px;          /* 头像固定 32px,绝不缩放 */
  width: 32px;
  height: 32px;
  border-radius: 50%;
}

.msg__bubble {
  padding: 8px 12px;
  border-radius: 12px;
  background: #f1f1f1;
  min-width: 0;            /* 允许长文本换行 */
  word-break: break-word;
}

.msg.mine .msg__bubble { background: #d2e8ff; }

这个组件把 Flexbox 的多个特性用到位:flex-direction 决定纵向堆叠、align-self 让单条消息独立对齐、row-reverse 复用同一套 DOM 实现左右镜像、flex: 0 0 头像固定、min-width: 0 保证长文换行。整个气泡列表无需一行 JS 定位。

inline-flex 与 flex 的区别

display: flex 让容器成为块级弹性盒(独占一行),display: inline-flex 则让容器像文字一样内联排布(可与文本并排),但两者内部的弹性布局规则完全一致。

cssCode
/* 块级:徽章独占整行 */
.block-badge { display: flex; align-items: center; gap: 4px; }

/* 内联:图标 + 文字组成的小标签,可嵌在句子中间 */
.inline-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: #eef2ff;
}

选择依据很简单:需要和周围文字同行排布用 inline-flex,需要独占一行用 flex。

总结

| 维度 | 关键点 |

| --- | --- |

| 定位 | 一维布局模型,管理一行或一列 |

| 两条轴 | 主轴由 flex-direction 决定,交叉轴与之垂直 |

| 主轴对齐 | justify-content(start/center/between/around/evenly) |

| 交叉轴对齐 | align-items(单行)/ align-content(多行)/ align-self(单项) |

| 项目伸缩 | flex-grow / flex-shrink / flex-basis,简写 flex |

| 常用值 | flex:1 等分、flex:auto 按内容、flex:none 固定 |

| 高频坑 | flex-shrink 压扁、min-width:auto 溢出 |

| 适用场景 | 居中、导航栏、等高卡片、标签流、自适应分栏 |

一句话记忆:Flexbox 让「沿一条线排布和对齐」变得声明式而优雅——先想清楚主轴方向,再决定主轴分布(justify-content)与交叉轴对齐(align-items),最后用 flex 简写控制每个项目的伸缩,绝大多数一维布局都能三步搞定。