Flex Item Distribution
A practical guide to evenly and proportionally distributing flex items using flex-grow, flex-shrink, and flex-basis.
有个布局需求:多个卡片,每行 4 个,超出换行,每个卡片宽度一致。
最直接的想法是 flex: 1:
1
2
3
4
5
6
7
8
.main {
display: flex;
flex-wrap: wrap;
.item {
flex-grow: 1;
height: 100px;
}
}
前几行看起来没问题,但最后一行如果只有 2 个卡片,flex-grow: 1 会让它们平分剩余空间,变成两倍宽——不是想要的效果。
问题出在 flex-grow 的定义上:它分配的是剩余空间,而不是绝对宽度。每个盒子的实际宽度 = 初始宽度 + 按比例分到的剩余空间。行末只有两个盒子,剩余空间就被这两个人平分了,当然会变宽。
要固定 4 列,重心应该放在 flex-basis 上——直接指定每个 item 初始占多大,而不是靠「分剩余空间」:
1
2
3
4
5
6
7
8
9
10
11
.main {
$gap: 15px;
display: flex;
flex-wrap: wrap;
gap: $gap;
.item {
height: 100px;
border-radius: 10px;
flex: 0 0 calc((100% - 3 * $gap) / 4);
}
}
flex: 0 0 calc(...) 展开是 flex-grow: 0、flex-shrink: 0、flex-basis: calc((100% - 3 * $gap) / 4)。flex-grow: 0 是关键,它保证了最后一行即使不满 4 个,每个 item 也不会扩张去填空位。
flex-grow 本身不是没用,用对场景就很方便。最常见的是几个盒子在同一行里撑满容器,比如 tab 栏、表头——各盒子没有固定宽度,内容量差不多,flex-grow: 1 就够了(简写 flex: 1):
1
2
3
4
5
6
7
8
.main {
display: flex;
height: 200px;
.item {
flex-grow: 1;
height: 100%;
}
}
如果盒子里有内容,情况就不一样了。一个盒子有文字、另一个是空的,初始宽度不同,flex-grow 分完之后三个盒子仍然不等宽——只是剩余空间是均分的。
如果确实要等宽,加上 flex-basis: 0 把初始空间清零,再用 flex-grow 均分,结果就一致了:
1
2
3
4
.item {
flex-grow: 1;
flex-basis: 0;
}
flex-shrink 控制的是缩小比例,默认为 1——空间不足时等比例缩小。一般不用改,用默认值就行。







