CSS Handbook · 布局

第六章 / 6.3 Flexbox 详解

第六章 · 6.3 节

Flexbox 详解


Flexbox(弹性盒布局)是为一维排布而生的系统:无论是一行导航链接、一组等高卡片,还是一个需要在容器中垂直水平都居中的元素,Flexbox 都能用寥寥几行声明式代码解决,彻底终结了 float 时代靠 hack 凑布局的历史。

主轴与交叉轴

理解 Flexbox 的第一把钥匙,是分清"主轴"(main axis)与"交叉轴"(cross axis)——几乎所有 flex 属性都是围绕这两条轴展开的。

flex-direction: row(默认)时的轴向
↑ 交叉轴
1
2
3
主轴 →

flex-direction 决定主轴方向:row(水平,默认)、column(垂直)、以及它们的 -reverse 版本。交叉轴永远与主轴垂直——当主轴变为垂直方向时,"justify-content 控制水平"这类记忆方式就会失效,务必以主轴/交叉轴而非"水平/垂直"来理解。

容器属性

属性作用常用取值
display开启弹性布局flex / inline-flex
flex-direction主轴方向row / column / row-reverse
flex-wrap是否允许换行nowrap(默认)/ wrap
justify-content主轴对齐flex-start / center / space-between / space-around / space-evenly
align-items交叉轴对齐(单行)stretch(默认)/ center / flex-start / flex-end / baseline
align-content交叉轴对齐(多行整体)同 justify-content 取值,需配合 wrap
gap子项间距如 16px,或 row-gap/column-gap 分别设置
justify-content 对比
flex-start
A
B
center
A
B
space-between
A
B

子项属性

属性作用
order调整视觉排列顺序,不改变 DOM 顺序,默认值 0
align-self覆盖容器的 align-items,单独控制某一项的交叉轴对齐
flex-grow剩余空间的分配比例,默认 0(不主动拉伸)
flex-shrink空间不足时的收缩比例,默认 1(允许收缩)
flex-basis分配剩余空间前的"起始尺寸",默认 auto

grow / shrink / basis 换算

这三者常合写为简写 flex: grow shrink basis,是 Flexbox 中最容易"知道语法但不知道为什么"的部分。理解它的关键是想象一条计算流程:

  1. 浏览器先按每个子项的 flex-basis 计算"期望尺寸"之和;
  2. 与容器主轴尺寸比较:若有剩余空间,按 flex-grow 的比例分配给各子项;
  3. 若空间不足,则按 flex-shrink(并结合各自 basis 加权)的比例收缩各子项。
/* 常见简写 */
.item { flex: 1; }          /* 等价于 1 1 0%,均分剩余空间 */
.item { flex: auto; }       /* 等价于 1 1 auto,按内容尺寸伸缩 */
.item { flex: none; }       /* 等价于 0 0 auto,完全不伸缩 */
.item { flex: 0 0 200px;  } /* 固定 200px,不参与伸缩 */
flex: 1 1 0% — 三项均分剩余空间
flex: 1
flex: 1
flex: 1
flex: 2 1 0 / 1 1 0 / 1 1 0 — 按 2:1:1 分配
2
1
1

gap 间距

在 gap 出现之前,子项间距只能靠 margin 拼凑,还得处理"最后一项不需要间距"的边界情况。现在 gap 原生支持行列间距,且不会在容器边缘产生多余空白。

.container {
  display: flex;
  gap: 12px 20px; /* row-gap column-gap */
}

常见排布方案

方案一:导航栏两端对齐

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

方案二:完全居中

.center-box {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

方案三:等高卡片 + 底部按钮对齐

.card {
  display: flex;
  flex-direction: column;
}
.card .spacer { flex: 1; } /* 把按钮推到底部 */
效果预览:卡片内容不等长,按钮仍底部对齐
短标题
按钮
这是一段比较长的标题文字,会占用更多行
按钮

常见误区

  • 子项设置了固定宽度,却仍被 flex-shrink 压缩——记得配合 flex-shrink: 0 或 min-width: 0 排查。
  • align-items 默认值是 stretch,若子项高度"莫名"被拉伸,先检查是否显式设置了它。
  • 文本或图片子项不换行导致溢出,往往是因为 flex 子项的默认最小尺寸是内容尺寸,需要设置 min-width: 0 或 overflow 处理。

Chapter 6 · Section 6.3

Flexbox in Depth


Flexbox (flexible box layout) is a system built for one-dimensional arrangement: whether it is a row of navigation links, a set of equal-height cards, or an element that needs to be centered both vertically and horizontally, Flexbox solves it in a few lines of declarative code — finally ending the float-era habit of hacking layouts together.

The Main Axis and the Cross Axis

The first key to understanding Flexbox is telling the "main axis" apart from the "cross axis" — almost every flex property revolves around these two axes.

The axes with flex-direction: row (default)
↑ cross axis
1
2
3
main axis →

flex-direction decides the direction of the main axis: row (horizontal, default), column (vertical), and their -reverse variants. The cross axis is always perpendicular to the main axis — once the main axis becomes vertical, mnemonics like "justify-content controls horizontal" break down, so always think in terms of main axis / cross axis rather than "horizontal / vertical".

Container Properties

PropertyPurposeCommon values
displayEnables flex layoutflex / inline-flex
flex-directionMain axis directionrow / column / row-reverse
flex-wrapWhether wrapping is allowednowrap (default) / wrap
justify-contentMain-axis alignmentflex-start / center / space-between / space-around / space-evenly
align-itemsCross-axis alignment (single line)stretch (default) / center / flex-start / flex-end / baseline
align-contentCross-axis alignment (multiple lines as a whole)Same values as justify-content, requires wrap
gapSpacing between itemse.g. 16px, or row-gap/column-gap set separately
justify-content comparison
flex-start
A
B
center
A
B
space-between
A
B

Item Properties

PropertyPurpose
orderAdjusts the visual order without changing the DOM order; default 0
align-selfOverrides the container's align-items to control one item's cross-axis alignment individually
flex-growThe ratio for distributing remaining space; default 0 (does not stretch on its own)
flex-shrinkThe shrink ratio when space runs short; default 1 (allowed to shrink)
flex-basisThe "starting size" before remaining space is distributed; default auto

How grow / shrink / basis Work Together

These three are usually combined into the shorthand flex: grow shrink basis, the part of Flexbox where people most often "know the syntax but not the why". The key to understanding it is to imagine a calculation pipeline:

  1. The browser first sums each item's "desired size" based on flex-basis;
  2. It compares that with the container's main-axis size: if there is leftover space, it is distributed to items according to flex-grow;
  3. If space is insufficient, items shrink according to flex-shrink (weighted by their basis).
/* Common shorthands */
.item { flex: 1; }          /* equivalent to 1 1 0%, evenly divides the remaining space */
.item { flex: auto; }       /* equivalent to 1 1 auto, stretches and shrinks with content */
.item { flex: none; }       /* equivalent to 0 0 auto, no flexing at all */
.item { flex: 0 0 200px;  } /* fixed at 200px, does not participate in flexing */
flex: 1 1 0% — three items evenly share the remaining space
flex: 1
flex: 1
flex: 1
flex: 2 1 0 / 1 1 0 / 1 1 0 — distributed in a 2:1:1 ratio
2
1
1

The gap Property

Before gap existed, spacing between items could only be cobbled together with margins, and you had to handle the edge case of "the last item needs no margin". Now gap natively supports both row and column spacing, and it never adds extra space at the container's edges.

.container {
  display: flex;
  gap: 12px 20px; /* row-gap column-gap */
}

Common Layout Patterns

Pattern 1: A navbar aligned at both ends

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

Pattern 2: Perfect centering

.center-box {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

Pattern 3: Equal-height cards with bottom-aligned buttons

.card {
  display: flex;
  flex-direction: column;
}
.card .spacer { flex: 1; } /* pushes the button to the bottom */
Preview: card content differs in length, but the buttons still align at the bottom
Short title
Button
This is a fairly long title that takes up more lines
Button

Common Pitfalls

  • An item has a fixed width but still gets compressed by flex-shrink — remember to investigate with flex-shrink: 0 or min-width: 0.
  • The default of align-items is stretch; if an item's height is "mysteriously" stretched, first check whether it was set explicitly.
  • Text or image items that refuse to wrap and overflow usually happen because a flex item's default minimum size is its content size; set min-width: 0 or handle it with overflow.