学完这篇,你能一次搞清 Flex 布局里最容易翻车的十来个场景,遇到问题直接查表改代码,不用再去搜索引擎里翻半天。
Flex 的 API 本身只有十来个属性,但组合起来的行为常常反直觉。下面按「现象 → 原因 → 改法」的顺序整理,每一条都给出可直接复制的代码。
第一步:先记住两个默认值
很多问题都源于没记住默认值:
- 主轴方向:
flex-direction: row
- 单行不换行:
flex-wrap: nowrap
- 主轴对齐:
justify-content: flex-start
- 交叉轴对齐:
align-items: stretch(子项会被拉伸到等高)
- 子项放大:
flex-grow: 0;收缩:flex-shrink: 1;基准:flex-basis: auto
注意:flex-shrink 默认是 1,意味着空间不够时子项会「主动被压缩」,这是下面很多问题的根源。
第二步:子项宽度被压扁 / 文字被挤成竖排
现象:给子项设了 width: 200px,容器变窄后它还是被压小;或者文本内容被挤成一列一个字。
原因:flex-shrink: 1 允许收缩,且子项的 min-width 默认是 auto(按内容最小宽度算)。
改法二选一:
/* 方案 A:禁止收缩,宽度锁死 */
.item { flex: 0 0 200px; }
/* 方案 B:允许收缩,但让文字正常省略 */
.item { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
注意:在 flex 子项里直接写 text-overflow: ellipsis 经常不生效,缺的就是 min-width: 0。这是最经典的坑。
第三步:flex: 1 和 flex: auto 到底差在哪
flex: 1 等价于 flex: 1 1 0% → 基准为 0,所有子项平分剩余空间。
flex: auto 等价于 flex: 1 1 auto → 基准为内容宽度,内容多的分到更多空间。
做「左边定宽、右边自适应」的经典布局:
.layout { display: flex; }
.sidebar { flex: 0 0 240px; }
.main { flex: 1; min-width: 0; }
注意:写 flex: 1 会同时把 flex-shrink 重置为 1,如果你前面单独设过 flex-shrink: 0,顺序反了就会被覆盖。简写属性永远写在具体属性前面。
第四步:垂直居中
.box {
display: flex;
justify-content: center; /* 水平 */
align-items: center; /* 垂直 */
}
如果容器高度是 auto,垂直居中看不出效果 —— 先给它一个确定高度,或者用 min-height: 100vh。
第五步:让某个子项单独靠右
不用 justify-content,给它加自动外边距即可:
.nav { display: flex; }
.nav .right { margin-left: auto; }
同理,margin: auto 用在 flex 子项上会吃掉所有剩余空间,是 flex 里最好用的技巧之一。
第六步:多行布局的间距
老写法靠 margin 然后负边距抵消,现在直接:
.list { display: flex; flex-wrap: wrap; gap: 16px; }
gap 不会在首尾多出间距,比 margin 干净得多。多行时纵向对齐由 align-content 控制:
.list { align-content: flex-start; } /* 默认 stretch,会把行高撑开 */
注意:justify-content 管主轴,align-content 管多行整体,align-items 管单行内部。三个别混用。
第七步:子项高度撑不满 / 容器高度塌陷
align-items: stretch 默认生效的前提是子项没设固定高度。一旦给子项写死 height,它就不会再等高。
在「外层滚动、内层 flex 撑满」时,常见现象是滚动区不生效,原因是外层没设 min-height: 0:
.page { display: flex; flex-direction: column; height: 100vh; }
.body { flex: 1; min-height: 0; overflow-y: auto; }
注意:min-height: 0 和前面提到的 min-width: 0 是一对,凡是「flex 子项 + 滚动/省略号/溢出」的场景,先补上它。
第八步:子项里的图片被拉伸变形
.card img { width: 100%; height: 100%; object-fit: cover; }
.card img { flex-shrink: 0; } /* 多图并排时防止被压扁 */
object-fit: cover 保证等比裁切填充,contain 则是完整显示留白。
第九步:调整显示顺序
.item-b { order: -1; } /* 数字越小越靠前,默认 0 */
只影响视觉顺序,不影响 DOM 与键盘 Tab 顺序。纯视觉排序可以用,涉及交互顺序时要谨慎。
第十步:排查顺序建议
遇到 flex 问题按这个顺序过一遍,基本能定位:
- 容器是否真的
display: flex(被别的规则覆盖没)
flex-direction 是什么,主轴是哪条
- 子项的
flex-grow / shrink / basis 实际值
- 有没有
min-width: 0 / min-height: 0
- 内容本身是不是最小宽度撑住了(长单词、长 URL、表格)
小结
flex-shrink 默认 1,宽度被压先查它,锁死用 flex: 0 0 Npx。
- 省略号不生效,八成是漏了
min-width: 0。
flex: 1 是平分(basis 0),flex: auto 是按内容分(basis auto)。
- 垂直居中要配合确定高度,否则看不出效果。
- 单侧靠右用
margin-left: auto,最省事。
- 多行间距用
gap,纵向对齐看 align-content。
- 滚动容器塌陷补
min-height: 0。
- 排查顺序:方向 → grow/shrink/basis → min-* → 内容最小宽度。