Skip to main content

Flex 布局:12 个属性分工

· 6 min read

Flexbox 是 容器定方向,子项定大小 两套属性加起来 12 个的事。

  1. 启动display: flex 一行,元素变弹性容器
  2. 容器 6 属性:flex-direction / flex-wrap / justify-content / align-items / align-content / gap
  3. 子项 6 属性:flex-grow / flex-shrink / flex-basis / flex / order / align-self
  4. 核心思路:先想主轴(默认水平),再选对齐方式
  5. 现代选择gap 替代 margin 间距
  6. 常见坑主轴 / 交叉轴搞反,90% 的 flex bug 都是这个
  7. 默认行为grow=0 / shrink=1不抢必缩

启动:display: flex

.container { display: flex; }

一行,直接子元素 变 flex item,参与弹性布局。inline-flex 是行内版本(容器本身按 inline 处理)。

下面是一张经典的 Flexbox 速查图,把所有 12 个属性的常见值摆在一起,可以作为后面属性表的视觉参考:

两套属性,12 个

容器属性(写在 display: 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
align-items交叉轴 对齐(单行)stretch / center / flex-start / flex-end
align-content多行之间的交叉轴对齐stretch / center / flex-start / space-between
gap子项间距<length> 或百分比

子项属性(写在直接子元素上):

属性作用常见值
flex-grow主轴剩余空间分配比例0(默认不抢)/ >= 0
flex-shrink空间不够时的收缩比例1(默认收缩)/ >= 0
flex-basis弹性生效前的初始尺寸auto(默认)/ <length> / 0
flexgrow / shrink / basis 缩写flex: 1(最常见)
order显示顺序(覆盖源码顺序)整数,默认 0
align-self覆盖容器的 align-itemsalign-items

主轴 / 交叉轴:90% 的困惑在这里

主轴 默认是水平(row)。交叉轴 垂直于主轴。

切换方向:flex-direction: column → 主轴变垂直,交叉轴变水平。所有 justify-content / align-items 的语义跟着换。

.row { display: flex; flex-direction: row; }
.column { display: flex; flex-direction: column; }
  • row:水平是主轴 → justify-content 管水平,align-items 管垂直
  • column:垂直是主轴 → justify-content 管垂直,align-items 管水平
关键提醒

justify-content 永远管主轴,align-items 永远管交叉轴——和方向无关。记不住就在脑子里默念这条规则。

flex 缩写的真实含义

最常用的写法是 flex: 1,但很多人不知道它展开后是什么:

.item { flex: 1; } /* = flex: 1 1 0% — 抢剩余空间,平分 */
.item { flex: auto; } /* = flex: 1 1 auto — 按内容大小伸缩 */
.item { flex: none; } /* = flex: 0 0 auto — 完全固定尺寸 */
.item { flex: 0 1 auto; } /* = flex: initial — 默认行为 */

flex-grow 计算公式

剩余空间按 grow 比例瓜分:

flex-shrink 计算公式

超额空间按 width × shrink 比例分摊:

弹性盒子中元素的总长度肯定不能超过盒子的长度,但可以小于盒子的长度。grow 默认是 0(不主动抢剩余空间),shrink 默认是 1(按比例压缩避免溢出)。

flex: 1 是布局主力 —— "抢剩余空间,平分"。三栏等宽布局就是每个 .col { flex: 1 }

注意坑flex: 1 在标准里是 1 1 0%不是 1 1 000% 在 flex 上有微妙差别(涉及 min-content 计算),多数情况下看不出区别,但极端场景下会触发不同行为。

gap:现代间距写法

传统写法用 margin

.item + .item { margin-left: 16px; } /* 老写法:要选第一个 */
.item:not(:last-child) { margin-right: 16px; }

现代写法直接 gap

.container { display: flex; gap: 16px; } /* 一行搞定 */

gap 在 2021 年所有浏览器都支持,margin 干净一个量级。Flex、Grid、多列布局通用。

实战 3 场景

场景 1:垂直居中(Flex 最经典的用法)

.center { display: flex; justify-content: center; align-items: center; }

一行解决 2009 年需要 position + transform 才能搞的事。

场景 2:三栏等宽布局

.row { display: flex; }
.col { flex: 1; } /* 三栏都设 flex: 1,自动平分 */

中间栏固定,两边平分剩余:

.col-side { flex: 1; }
.col-main { flex: 0 0 600px; } /* 固定 600px */

场景 3:响应式工具栏

.toolbar {
display: flex;
flex-wrap: wrap;
gap: 8px;
}

子项超出容器自动换行。配 flex: 1 1 200px(最小 200px,能伸缩能换行),就是经典 auto-fill 卡片布局的雏形。

常见误区

  1. flex: 1 不等于 width: 100% —— 前者是"分剩余空间",后者是"固定占满"。多列布局用前者,单独元素用后者。
  2. margin 在 flex item 上不合并 —— 父子 margin collapse 在 flex 容器里失效,需要靠 gap 或显式 margin。
  3. align-items: stretch 跨方向变形 —— 默认让子项填满交叉轴,但设了 height / aspect-ratio 后失效。
  4. flex-basis: 50% 不含 padding —— 老坑,百分比的 flex-basis 可能让子项超出容器。
经验

flex 调试用浏览器 DevTools 的 Flexbox inspector(Chrome / Firefox 都自带),比盲改效率高 10 倍。

References

  1. MDN Flexbox —— 完整参考
  2. CSS Tricks: A Complete Guide to Flexbox —— 经典可视化指南
  3. W3C Flexbox Spec —— 规范源