先记住这个答案
卡片加了 flex-wrap: wrap 后,第二排只有一张卡片却铺得很宽,这是 Flex 的正常表现。浏览器先把项目分到各条线上,然后在每条线内部单独计算 flex-grow、flex-shrink 与 justify-content。它不会沿用第一排的列宽;如果产品要求每行形成严格对齐的网格,通常应改用 Grid。
wrap允许项目分配到多条线- 排线要计入尺寸与间距
- 每条线独立分配剩余空间
- 末行项目可能被单独拉宽
卡片从一行变成多行
卡片容器宽度缩小时,四张卡片从一行变成两行。项目的 flex-basis、外边距和 gap 会一起影响能否放下;只盯住卡片的 width 容易算错临界点。比如三个 100px 卡片与两段 16px 间距至少需要 332px,容器比它窄就可能把第三张放到下一行。最终宽度还可能因每行自己的 flex-grow 改变。
.cards {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 180px; /* 以 180px 为排线基准 */
min-width: 0;
}卡片的 180px 基准尺寸用于排线;最后一行能否拉满取决于各项 flex-grow。
每条 Flex 线分别伸缩
Flex 换行不是把整行排完后才统一缩小,它先决定哪些项目同属一条 Flex 线,再在每条线内部处理增长和收缩。因此 flex: 1 1 180px 的卡片到了只有一张的末行,可能独自长满整行。交叉轴上,行与行的分布由 align-content 管;单行内部项目在交叉轴的对齐由 align-items 管。容器交叉尺寸没有多余空间时,align-content 的空间分布也可能看不出变化。
换行判断看的是项目的外部假设主尺寸,而不是等每个项目缩到零才换行。比如卡片基础宽度 220px、容器宽度 500px、gap: 20px,两张卡片能进同一行,第三张需要另起一行。若卡片写了 flex-grow: 1,第一行的两张会分享该行余量,第二行孤单的一张可能撑满整行。想得到固定三列且上下严格对齐的卡片阵列,Grid 的列轨道更直接。
容易答错的地方
- 以为
wrap会保持严格网格列对齐 - Flex 的每一行独立计算宽度,最后一行可能被拉宽。需要跨行列轨严格对齐时,Grid 通常更合适。
- 忽略
gap和外边距 - 它们都占空间,卡片宽度总和刚好等于容器宽度时,间距仍可能迫使换行。
面试官还会怎么问?
一张卡片比容器还宽怎么办?
Flex 可以在它前面断行,却不能把单张项目拆成多行。要允许项目自身收缩、让内容断词,或处理横向溢出。
align-content 和 align-items 分别管什么?
前者分配多条 Flex 线在交叉轴上的空间,后者对齐每条线里的项目。只有一条线时前者通常没有可分配的线间空间。
为什么末行只有一张卡片时会铺满?
它所在的行独立计算正向剩余空间;如果项目有 flex-grow: 1,这张卡片就能拿到整行余量。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。