HandyTools Hub

← 全部指南

CSS Flexbox 详解:弹性布局模型的轴、对齐、尺寸与间距

2026-08-17

你在容器上写了 display: flex,三个盒子排成一行。然后 justify-content: center 生效了,align-items: center 却做出你完全没想到的效果;一个长单词把整个布局撑爆;子项还在你没要求的情况下神秘地变小了。Flexbox 是 CSS 里用得最多也最被误解的布局方式,因为它自带一套前所未有的心智模型——。一旦这个模型通了,整张属性表就顺理成章。本文从第一性原理把它讲透。

两根轴:主轴与交叉轴

每个 flex 布局都有两根轴,所有 flex 属性都定义在其中之一上。这一件事就能澄清大部分困惑:

  • 主轴(main axis)——子项排列的方向,由 flex-direction 决定。
  • 交叉轴(cross axis)——与主轴垂直的方向。

flex-direction: row(默认值)让主轴水平——子项从左到右排成一排,交叉轴垂直。flex-direction: column 则互换:子项从上到下堆叠,交叉轴水平。

由此推出两个结论:

  • justify-content 沿主轴分配子项。
  • align-items 沿交叉轴摆放子项。

这就是经典的混淆来源:人们因为单词里有 “align” 就以为 align-items 是水平居中。在 row 布局里它负责的是垂直方向。今后任何属性”不生效”,先问一句:它作用在哪根轴上,那是我想作用的轴吗?

容器与子项

display: flex 把这个元素变成 flex 容器,它的直接子元素变成 flex 子项。由此推出两件事:

  • 只有直接子元素是 flex 子项。孙元素在父元素不是 flex 容器时仍是普通块级元素——所以真实布局要嵌套 flex 容器。
  • 容器和子项的属性集合互不重叠。容器属性(flex-directionflex-wrapjustify-contentalign-itemsalign-contentgap)负责排列;子项属性(flex-growflex-shrinkflex-basisalign-selfordermargin)控制子项自身的尺寸和位置。

主轴:方向、分布、换行、间距

方向。 flex-direction 取值 rowrow-reversecolumncolumn-reverserowcolumn 最常用;-reverse 变体镜像起点和终点(阿拉伯语布局和精细视觉排序时会用到)。

分布。 justify-content 决定主轴上剩余空间怎么分配:

  • flex-start / flex-end——子项挤向起点或终点(默认是 flex-start)。
  • center——聚在中间。
  • space-between——两端无空隙,子项之间等距。
  • space-around——每个子项两侧等距(两端各留半个间距)。
  • space-evenly——处处等距,包括两端。

换行。 默认 flex-wrap: nowrap 把所有子项压在一行上,装不下就压缩或溢出。flex-wrap: wrap 让子项放不下时换到新行——这是响应式卡片行、徽章行的关键开关。

间距。 gap(配 row-gapcolumn-gap 分轴设置)定义子项之间的间距。它取代了老旧的 margin + nth-child 技巧,而且不像 margin 会在边缘重复叠加。

交叉轴:align-items、align-content、align-self

align-items 沿交叉轴摆放子项。它的默认值 stretch 是个坑:子项会拉伸填满容器的交叉尺寸,除非它自己的宽高(或 align-self)另有指定。其他取值:flex-startflex-endcenterbaseline(按文字基线对齐,适合不同高度的按钮行或表单标签)。

align-content 看起来是同类,但只在子项换行成多行时生效——它沿交叉轴分配的是行本身。只有一行子项时它什么都不做,这是”为什么没居中”的又一常见来源。

align-self 为单个子项覆盖 align-items——一排元素里想让某个掉到底部、其余居中时很好用。

子项尺寸:flex-grow、flex-shrink、flex-basis

三个子项属性决定主轴上每个子项的实际大小:

  • flex-basis——子项在缩放之前的初始主轴尺寸。默认 autowidth/height 或内容尺寸;0 表示”从零开始,完全由 grow 份额决定”。
  • flex-grow——所有子项按 basis 排完后还有剩余空间,就按 grow 值的比例分给各子项。默认 0(不增长)。
  • flex-shrink——basis 总和超出容器时,子项按 shrink 值的比例压缩。默认 1

默认的 flex-shrink: 1 就是”没让你缩你却缩了”的元凶:任何含固定宽度子项的 flex 容器在溢出时都会悄悄把它们压扁。两种停法:flex-shrink: 0,或者缩写 flex: none

缩写把三者打包:flex: 1 等于 1 1 0%(等分增长、可压缩、忽略 basis),flex: auto 等于 1 1 auto(等分增长但尊重内容尺寸),flex: none 等于 0 0 auto(永不增减)。flex: 2 增长速度是 flex: 1 兄弟项的两倍。

还有一个坑:flex 子项默认(min-width: auto)拒绝缩到比最小内容尺寸还小。子项里的长单词或大图因此怎么缩都会溢出——解决办法是在子项上设 min-width: 0(或 overflow: hidden)。

经典错误

  • justify-contentalign-items 用反。 先问自己在哪根轴上。row 布局里水平是 justify-content、垂直是 align-items;column 布局两者对调。
  • “垂直居中不生效。” 你在 row 的交叉轴上居中——该用 align-items: center,不是 justify-content: center
  • “为什么我的子项在缩小?” 默认 flex-shrink: 1。固定 flex-shrink: 0 或用 flex: none
  • “文字溢出且修不好。” min-width: auto 阻止缩到内容宽度以下;给出问题的子项设 min-width: 0
  • 用 margin 做间距。gap,它就是为此而生的。
  • 居中的一行代码。 flex 子项的 margin: auto 会吸收全部剩余空间,所以单个 margin: auto 的子项会在两根轴上都居中——不需要任何 flex 属性的”完美居中按钮”经典技巧。

用嵌套 flex 搭建真实布局

flex 在小组合里最出彩。导航头部是一个 justify-content: space-between(logo 靠左、链接靠右)加 align-items: center 和链接间 gap 的容器。工具栏是一排 align-items: center 的子项。带图标和两行文字的卡片是 column 方向的 flex 容器,子项之间留 gap。要做”侧栏 + 内容”的两栏页面壳,可以让内容列 flex: 1,侧栏保持固定宽度,主区域吸收剩余空间。

一旦布局需要同时在二维对齐——整页骨架、行列都要对齐的卡片网格——flexbox 就不够用了。那是 CSS Grid 的职责:grid 一开始就同时定义行列,flexbox 一次只排一根轴。常见的架构是:网格搭整页骨架,flexbox 在每个单元格内部做精细对齐,两者配合得天衣无缝。

速查

  • flex-direction 决定主轴(row = 水平,column = 垂直);交叉轴与它垂直。
  • justify-content 作用在主轴,align-items 作用在交叉轴。
  • 默认 align-items: stretch——子项填满交叉尺寸,除非另有指定。
  • flex-wrap: wrap + gap = 无需 margin 技巧的响应式行。
  • flex-basis = 初始尺寸,flex-grow = 剩余空间份额,flex-shrink = 压缩速度。flex: 1 = 1 1 0%flex: none = 0 0 auto
  • 子项默认会缩(flex-shrink: 1),且拒绝缩到内容尺寸以下(min-width: auto)——被咬到就钉住其中一个。
  • 一次一根轴用 flexbox,二维布局用 grid

想可视化设计 flex 布局?CSS Flexbox Generator 让你拖拽对齐和尺寸选项并直接复制成品 CSS;CSS Grid Generator 对 grid 做同样的事。