CSS 教程 / Flexbox 基础:容器、项目与轴
Flexbox 沿着主轴排列容器的直接子项目,并沿该轴分配空间。flex-direction 选择主轴方向,而交叉轴垂直于主轴;row 并不总是表示水平方向。
选择一个 Flexbox 容器及其项目
Flexbox 适合用于一维关系,例如导航项、按钮旁的搜索字段或图标旁的描述。使用重复空格或独立定位的元素来排列这些内容很脆弱,因为内容和可用宽度会发生变化。Flexbox 会将容器的可用空间分配给其直接子元素。
如果你需要一个能够同时一致对齐行和列的网格,请查看 Grid。Flexbox 也可以分成多行,但每一行的空间分配是独立的,因此第一行的列不一定和第二行的列对齐。页面的大区域可以作为一个整体的 Grid 使用,其中的按钮集合可以像 Flexbox 一样使用。要同时对齐多行多列,请参考 CSS Grid 基础:轨道、线条和项目放置,它可以一起创建行和列。
.menu {
display: flex;
gap: 12px;
}
这条规则不负责设置 .menu 本身在其父级中的排布方式。它设置的是 .menu 内部直接子元素的布局。例如,如果你在 .menu 内有两个 div,并且在第一个 div 内有两个 span,那么 Flex 项目是两个 div。如果你想水平排列 span,你必须在那个 div 中另外指定一个 display: flex。
识别主轴和交叉轴
主轴是 Flex 项目排列的方向,交叉轴是垂直于主轴的方向。与其记住哪个属性控制宽度或高度,不如理解哪个轴控制它,这样即便将布局改为列,也能准确对齐。
| flex-direction | 通用水平书写,从左到右的文档顺序 | 主轴/交叉轴 |
|---|---|---|
| row | 从左到右 → | 水平 / 垂直 |
| row-reverse | 从右到左 → | 水平 / 垂直 |
| column | 从上到下 → | 垂直/水平 |
| column-reverse | 从下到上 → | 垂直/水平 |
此表中的方向假设writing-mode: horizontal-tb和direction: ltr。在从右到左或纵向书写时,物理方向会发生变化。row遵循内联方向,因此它并不总是从左侧开始。有关详细信息,请参见MDN:Flexbox 基本概念。该指南进一步解释了轴与书写方向的关系。
了解初始的 Flexbox 行为
如果未指定单独的值,flex-direction 为 row,flex-wrap 为 nowrap。项目会聚集在主轴的起点,并且不会自动沿主轴扩展以填充多余的空间。如果空间不足,它可能会缩小,但如果由于内容的最小尺寸或指定的约束而无法充分缩小,它可能会溢出到父元素之外。对对齐、换行和项目尺寸的详细控制将在 Flexbox 对齐、换行、gap、grow 与 shrink 中继续讲解。
交叉轴上的默认对齐表现为 stretch。在本例水平书写的 row 容器中,高度为 auto 的项目通常会填充相同的行高。这就是为什么短描述卡看起来与长描述卡高度相同的原因。不要假设已经有明确高度或自动边距的项目会自动拉伸。在本例的 column 容器中,交叉轴是水平的,因此宽度看起来会增加。
项目的初始调整大小可以理解为flex: 0 1 auto。0表示不要通过占用剩余空间来放大,1表示在空间不足时参与缩小,而auto表示以相应主轴的尺寸规格和内容为基础。在此阶段,首先检查放置方向和基本操作,而调整比例和换行的实践将在对齐和尺寸调整课程中详细讲解。
比较普通流和Flexbox方向
将以下代码保存为 UTF-8 文件 flex-direction.html 并在浏览器中打开。无需单独的库。所有链接按 First、Second、Third 的顺序编写,只有 CSS 不同。一般布局部分将链接指定为块,并逐行显示。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>flex-direction.html</title>
<style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.demo { border: 2px dashed #789; padding: 12px; margin-bottom: 20px; }
.demo > a, .nested > div { padding: 12px; background: #dceefa; }
.normal > a { display: block; margin-bottom: 8px; }
.row, .column, .reverse, .nested { display: flex; gap: 12px; }
.column { flex-direction: column; }
.reverse { flex-direction: row-reverse; }
.nested > div { flex: 1; min-width: 0; }
.nested span { display: block; }
.initial { display: flex; gap: 12px; border: 2px dashed #789; }
.initial > div { width: 180px; min-width: 0; padding: 12px; background: #e8f5de; }
</style>
</head>
<body>
<h1>Same HTML order, different placement</h1>
<h2>Normal block flow</h2><div class="demo normal"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>row</h2><div class="demo row"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>column</h2><div class="demo column"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>row-reverse</h2><div class="demo reverse"><a href="#result">First</a>
<a href="#result">Second</a>
<a href="#result">Third</a></div>
<h2>Direct and nested children</h2><div class="demo nested"><div><span>First line of box A</span><span>Second line of box A</span></div><div>Box B</div></div>
<h2>Initial size and growth</h2><div class="initial"><div>Short description</div><div>Two-line description<br>Second line</div><div>Three-line description<br>Second line<br>Third line</div></div>
<p id="result">This is the link destination. Use the links above to check keyboard navigation order.</p>
</body>
</html>
- 在 row 部分,确保三个项目在同一行。只需向 .row 添加 flex-direction: column 即可将其改为垂直排列。确认后,删除该声明并将其恢复为原来的行布局。
- 注意 column 部分的链接在水平方向上变宽。向 .column 添加 align-items: flex-start 会使链接更接近内容的宽度。这是因为 column 的交叉轴是水平的。比较后,删除添加的声明。
- 在 row-reverse 部分,First 显示在右侧,HTML 顺序仍为 First、Second、Third。按 Tab 确认焦点仍按这个 HTML 顺序移动。reverse 改变视觉排列,不会同步改变 DOM 或正常键盘顺序;不要用它修正重要内容的阅读顺序。
- 在嵌套的子部分中,只有大盒子 A 和 B 是并排放置的。A 中的两个 span 是垂直的。给 .nested > div 添加 display: flex,A 内部的两个 span 也会开始参与各自父元素的 Flex 布局。检查完后请删除添加的声明。
- 在最后一部分,确保三张卡片的高度相同,并且在宽屏幕上,每张卡片不会填满剩余的整个宽度。缩小屏幕会减少卡片宽度而不换行。如果你在 .initial > div 上添加 flex-shrink: 0,它将不会缩小,从而导致水平溢出。在检查后删除添加的声明。
诊断意外的布局结果
在开发者工具中,选择实际的父元素,而不是只选择需要排列的子元素,然后检查 display 的应用值。接下来,检查容器的 flex-direction,以及子元素的 width、height、min-width 和 margin。如果 flex 被其他规则覆盖,或者排序目标在更深一层,你将无法获得预期的结果。
换行不同于更改行和列。在一条水平线溢出的情况下,你必须首先决定列是否合适,以及是否需要使用 flex-wrap 来维持多行。如果内容在移动端被隐藏,先检查允许收缩的最小尺寸和阅读顺序,然后再用 overflow: hidden 隐藏它。未启用工作区保存或本地覆盖时,开发者工具中的临时修改可以通过刷新恢复,如果你修改了文件,需要自己还原任何保存的值。





