flex-grow / flex-shrink:剩余与亏空空间如何分配
简写一页讲清了 flex: 1 展开成哪三个值,这一页只看其中的分配过程:把每个 item 的 flex-basis 加起来,与容器主轴尺寸一比,要么有剩余(flex-grow 按比例瓜分)、要么不足(flex-shrink
按比例收缩)——两者互斥,同一时刻只有一个在工作。拖容器宽度越过临界点,下面用预测算式与 getBoundingClientRect 实测逐项对照。
两个默认值定了基调: flex-grow: 0(默认不瓜分剩余,于是容器变宽时项不跟着长、右侧留白)、flex-shrink: 1(默认可收缩,于是容器变窄时项一起缩而非溢出)。把容器宽拖过 Σbasis + 间距 这条临界线,就在 grow 区与 shrink
区之间切换。
1 · 拖容器宽,逐项对照预测与实测
三个 item 各有独立的 grow / shrink / basis(可改),并统一设 min-width: 0 解除自动最小尺寸下限,使浏览器的分配可被算式精确预测。色条按比例画出 basis(实色)、间距(灰)、被瓜分的剩余(绿斜纹)或溢出的亏空(红斜纹)。
2 · grow 与 shrink:一枚硬币的两面
flex-grow |
flex-shrink |
|
|---|---|---|
| 默认值 | 0(不瓜分) |
1(可收缩) |
| 何时生效 | 有剩余空间(free > 0) | 空间不足(free < 0) |
| 分配权重 | 直接按 grow 比例:+ free × growᵢ / Σgrow |
按 $shrink \times basis$ 加权:+ free × (shrinkᵢ·basisᵢ) / Σ(shrink·basis) |
| 全为 0 时 | 不瓜分,右侧留白 | 不收缩,内容溢出 |
两者不会同时生效:free 非负时只有 grow 参与、为负时只有 shrink 参与。这也是为什么 flex: none(0 0 auto)的项既不长也不缩——两个开关都关掉了。
收缩的权重为何要乘 basis。 若只按 shrink 比例收缩,basis 很小的项可能被收成负数。规范让收缩量正比于
:basis 越大的项「可让出的份额」越多,收缩更平滑。本页算式即按此实现,所以预测值与实测基本吻合(末位差来自浏览器对 min/max 的逐项冻结迭代,这里做了简化)。
两个让 shrink「失灵」的常见情形。 其一,本演示特意设了 min-width: 0;真实项默认是 min-width: auto,收到 min-content(最长不可断词)就不再继续缩、转为溢出。其二,flex-wrap: wrap 时项宁可换行也不收缩到次行——换行后每行重新分配,多行的均衡问题见 flex-wrap: balance,各对齐属性的作用范围见 对齐属性全景。