导航、工具栏、卡片列表和表单按钮区都有一个共同点:一组相邻元素需要沿着一个方向排列,还要根据空间变化调整间距或尺寸。这正是 Flexbox 擅长处理的一维布局。
刚接触 Flexbox 时,属性看起来很多,其实可以先抓住三个问题:主轴朝哪里,剩余空间出现在哪条轴上,当前属性写在容器还是项目上。后面的换行、对齐和弹性尺寸,都是围绕这三个问题展开的。

Flexbox 按一条轴分配空间。即使项目换成多行,每一行也会单独计算主轴尺寸和分布。如果布局要求行与列同时对齐到固定轨道,Grid 通常更合适。
把 display: flex 或 display: inline-flex 写在父元素上,这个父元素就成了弹性容器,它的直接子节点则成为弹性项目。两种写法的内部布局规则相同,差别在容器自身如何参与外部排版:flex 生成块级容器,通常会占据一整行;inline-flex 生成行内级容器,可以和文字或其他行内盒并排。
<nav class="site-nav">
<a href="/">首页</a>
<a href="/guides">指南</a>
<a href="/about">关于</a>
</nav>.site-nav {
display: flex;
gap: 0.75rem;
}这里要留意“直接子节点”这个范围。链接内部的图标和文字仍按原来的规则排版,除非我们再把链接设为弹性容器。纯空白文本节点会被忽略,带内容的文本却可能形成无法直接选中的匿名弹性项目,所以需要参与布局的内容最好放进明确的元素中。
直接子元素进入弹性格式化上下文后会被“块化”。无论它原来是 span 还是 p,此时都按弹性项目参与排布。项目之间的外边距不会折叠,float 和 clear 不再影响弹性排布,vertical-align 也无法把项目推到容器底部。
我们常把 row 直觉地理解成“从左到右”,但 Flexbox 并没有把这两个概念绑定在一起。flex-direction 的四个值需要结合 writing-mode 和 direction 来看:
row:主轴沿当前书写模式的行内方向。row-reverse:与 row 使用同一条轴,但交换主轴起点和终点。column:主轴沿块方向。column-reverse:与 column 使用同一条轴,但交换主轴起点和终点。.toolbar { display: flex; flex-direction: row; }
.sidebar { display: flex; flex-direction: column; }项目从 main-start 沿主轴排向 main-end。允许换行后,新行再从 cross-start 沿交叉轴堆叠到 cross-end。主轴上的尺寸叫 main size,交叉轴上的尺寸叫 cross size。
在常见的横排、从左到右页面中,row 的主轴通常从左向右,交叉轴从上向下。换到 RTL 或竖排文本后,物理方向就会改变。因此,理解轴线比记住“横向”和“纵向”更可靠。
可以把 justify-content 记成主轴分布,把 align-* 记成交叉轴对齐。这样即使切换 flex-direction,判断方式也不会失效。
默认值 flex-wrap: nowrap 会让所有项目留在同一条弹性行中。空间不够时,项目会先尝试收缩;如果内容最小尺寸或固定尺寸不允许继续缩小,内容就会溢出。改成 wrap 后,容器可以增加新的弹性行。wrap-reverse 同样允许换行,只是它交换了交叉轴的起点和终点,新行会向相反方向堆叠。
flex-flow 把 flex-direction 和 flex-wrap 合并到一条声明里,两个值的先后顺序不影响结果:
.cards {
display: flex;
flex-flow: row wrap;
gap: 1rem;
}反向排列改变的是视觉流向,不会改写 DOM。row-reverse 反转每一行的主轴方向,wrap-reverse 反转多行在交叉轴上的堆叠方向,两者也可以同时使用。

justify-content 写在容器上,处理每一条弹性行在主轴上的剩余空间。它不会像 flex-grow 那样改变项目尺寸,而是移动整组项目,或者把空白分配到项目之间。
start / flex-start:项目贴近主轴起点。end / flex-end:项目贴近主轴终点。center:整组项目居中。space-between:首尾贴边,中间间隔相等;一行只有一个项目时位于起点。space-around:每个项目两侧分到相同份额,所以相邻项目之间的空白是边缘空白的两倍。space-evenly:边缘与项目之间的所有间隔都相等。left 和 right 指向固定的物理方向,在需要适配不同书写方向时,通常不如 start 和 end 合适。在 Flexbox 中,normal 的效果等同于从起点分布;把 stretch 用在 justify-content 上也不会拉长项目。项目若已通过增长占满主轴,justify-content 自然就没有空白可分了。
.actions {
display: flex;
justify-content: space-between;
}如果容器禁止换行,而且项目总尺寸超过容器,start 通常会向主轴终点溢出,end 会向主轴起点溢出,center 则可能从两侧一起溢出。safe center 会在居中可能截断内容时尝试退回安全对齐;实际使用前,仍要在目标浏览器中确认支持情况。
align-items 写在容器上,规定每一行中所有项目默认如何沿交叉轴对齐。某个项目需要单独调整时,再把 align-self 写在这个项目上,覆盖容器给出的默认值。常用值有 stretch、start、end、center 和 baseline。
在 Flexbox 中,normal 通常表现为 stretch。不过,只有项目的交叉轴尺寸是 auto 时,拉伸才会明显发生;项目已经设置固定高度,stretch 不会强行覆盖这个高度。
如果一行里混有不同字号的文字、输入框和按钮,可以试试 baseline。first baseline 与 last baseline 分别指定首基线和末基线。在列方向等无法建立合适基线的场景中,它们会回退到起点或终点对齐。
.profile-row {
display: flex;
align-items: center;
}
.profile-row .status {
align-self: flex-start;
}自动外边距也能直接参与空间分配。主轴上的 margin-inline-start: auto 会先吸收可用空间,于是项目被推向主轴终点。把交叉轴两侧的外边距都设为 auto,则可以让单个项目在交叉轴上居中。因为自动外边距会优先拿走剩余空间,后续的对齐属性可能已经无处可调。
align-content 处理的是多条弹性行整体在交叉轴上的剩余空间。要看到效果,需要同时满足三个条件:容器允许换行,内容确实形成了多行,而且交叉轴上还有额外空间。单行容器通常看不出变化。
可用值包括 start、end、center、space-between、space-around、space-evenly 和 stretch。区分它和 align-items 的办法很直接:前者移动或拉开整行,后者对齐每一行内部的项目。
place-content 可以同时设置 align-content 和 justify-content。只写一个值时,两者使用同一个值;写两个值时,第一个控制交叉轴上的行分布,第二个控制主轴上的项目分布。
.gallery {
display: flex;
flex-wrap: wrap;
min-height: 28rem;
place-content: space-between center;
gap: 1rem 1.5rem;
}gap 是 row-gap 和 column-gap 的简写。它只在项目或弹性行之间留出固定间隔,不会给容器边缘增加空白,也没有外边距折叠的问题。在行方向的换行布局里,row-gap 通常控制行间距,column-gap 控制同一行中的项目间距。遇到其他方向时,再结合实际的行列关系判断。
下面这个实验把方向、换行、主轴分布和交叉轴对齐放在一起。你可以先保持 row 调整各项,再切到 column。这时原本的横向、纵向判断会跟着主轴改变,前面关于轴线的规则也会更直观。
计算弹性尺寸时,每个项目会先得到一个弹性基础尺寸。随后,浏览器判断主轴空间是有剩余还是不够,再进入增长或收缩阶段。flex-basis 指定空间分配前的主轴尺寸:主轴是行时,它接近起始宽度;主轴是列时,它接近起始高度。
flex-basis: auto:优先采用主轴方向显式 width/height,没有时参考内容。content、max-content、min-content 等内容关键字:按内容的内在尺寸求基础值。0:从零基础分配可用空间,常用于按增长因子得到比例列。当所有基础尺寸的总和小于容器时,多出来的空间会按照 flex-grow 的比例分配。下图中有 300px 剩余空间,增长因子是 1:2:3,三个项目因此分别得到 50px、100px 和 150px,再把这些数值加到各自 200px 的基础尺寸上。

基础尺寸总和超过容器时,就会出现负剩余空间,项目进入收缩阶段。这里不能只看 flex-shrink,收缩权重近似由 flex-shrink × flex-basis 决定。两个项目的收缩因子即使相同,基础尺寸更大的那个通常也要缩减更多。
实际计算还会受到 min-width、max-width 等边界影响。项目一旦碰到边界,浏览器会冻结它,再把尚未解决的差额分给其他项目。内容复杂时,一次简单的比例计算很难准确预测最终尺寸,最好在真实容器中检查结果。
.main { flex: 1 1 36rem; }
.aside { flex: 0 1 18rem; }弹性项目的自动最小主轴尺寸经常由内容决定,所以设置了 flex-shrink: 1,项目仍可能溢出。需要让内容继续收缩时,行方向的项目通常要加 min-width: 0,列方向则对应 min-height: 0。
flex 依次表示 flex-grow flex-shrink flex-basis。把三段都写出来,阅读时最容易确认每个项目如何增长、收缩,以及从什么基础尺寸开始计算:
.card { flex: 1 1 18rem; }常用预设的含义如下:
flex: initial → 0 1 auto:不主动增长,空间不足时允许收缩。flex: auto → 1 1 auto:以内容或显式尺寸为基础,既增长也收缩。flex: none → 0 0 auto:既不增长也不收缩。flex: 1 → 常见计算行为接近 1 1 0%:从近零基础平分可用空间,而不是简单等同于 flex-grow: 1。flex: 1 1 auto 会先保留各项目在内容或宽度上的差异,再分配剩余空间;flex: 1 1 0 则更接近等比分列。两种写法都可能被内容最小尺寸限制。
可换行的卡片列表常用 flex: 1 1 18rem。它表达得很清楚:项目的理想基础尺寸约为 18rem,可以增长,也可以收缩;当前行放不下时就换到下一行。相比手动计算百分比宽度,这种写法更能适应容器变化。
直接子元素改成绝对定位后,会脱离弹性布局,不再参与弹性行的空间分配。它的静态位置仍可能受到容器 justify-content 和自身 align-self 的影响;一旦写了 inset、top、left 等偏移,就按照定位规则放置。order 也可能改变它与兄弟元素的绘制先后,不过层叠关系应该交给定位和 z-index 等规则处理。
项目明明允许收缩却仍然溢出时,可以按下面的顺序排查:
min-width,列方向看 min-height。white-space: nowrap 与固定宽度。min-width: 0,并在内部设置合理的 overflow。flex: none 或 flex-shrink: 0。gap、边框、内边距也占空间。.shell { display: flex; }
.content { flex: 1 1 auto; min-width: 0; }
.content pre { overflow: auto; }order 的初始值是 0,也可以设置为负数或正数。浏览器先按 order 从小到大排列不同的顺序组,同一组内仍然遵循源码顺序。
row-reverse、column-reverse 和 order 都能改变视觉顺序,却通常不会同步改变 DOM、键盘焦点顺序或辅助技术的读取顺序。也就是说,画面看起来重新排列了,实际的交互顺序可能仍停留在原来的结构中。

.tabs { display: flex; }
.tabs .is-current { order: -1; }这段代码会让当前标签在视觉上排到最前面,但用户按 Tab 键时,焦点仍可能按源码顺序移动,于是屏幕上的焦点会来回跳动。我们应先让 HTML 表达正确的逻辑和阅读顺序,再用 CSS 做不会妨碍理解的视觉调整。不要用 order 把页脚移到标题前面,也不要用反向排列掩盖错误的 DOM 顺序。
这个实验可以切换项目的 flex 配置,并观察实际宽度如何变化。打开“视觉反转”后,再按 Tab 键依次访问按钮。你会看到视觉顺序和焦点顺序可能出现分歧,这也是结构顺序不能交给 CSS 修补的原因。
实际写 Flexbox 时,我们可以从轴线开始检查。先在父元素上建立弹性容器,再用 flex-direction 确定主轴,用 flex-wrap 决定是否允许增加弹性行。主轴上的剩余空间由 flex 和 justify-content 处理;一行内部的交叉轴对齐看 align-items 或 align-self,多行整体的分布看 align-content。项目之间的固定间隔可以交给 gap。
布局完成后,再检查项目的最小尺寸和溢出行为。只要使用了反向排列或 order,还要用键盘走一遍焦点顺序,确认视觉变化没有破坏阅读和操作逻辑。
.card-list {
display: flex;
flex-flow: row wrap;
gap: 1rem;
}
.card {
flex: 1 1 18rem;
min-width: 0;
display: flex;
flex-direction: column;
}
.card__actions
一段容易维护的 Flexbox 代码,通常不会依赖固定的左右方向,也不会用 order 修补结构。它会明确处理项目的收缩边界,并能说明每一处剩余空间由哪个属性分配。