flex-grow 分的是剩余空间,不是最终宽度 —— 两个手算例子

我见过不少人(包括我自己早期)把 flex-grow 当成”宽度占比”用:容器 1000px,三个子项分别写 grow 1 / 2 / 1,期望 250 / 500 / 250。

实际不是。grow 分配的是剩余空间,而剩余空间要先减掉每个子项的 flex-basis。

公式

剩余 = 容器宽度 − Σ flex-basis
每项增长 = 剩余 × (自身 grow / Σgrow)
最终宽度 = flex-basis + 增长

算例一:basis 不相等

容器 1000px,三个子项:

子项 flex-basis flex-grow 分到的剩余 最终宽度
A 200px 1 700 × 1/4 = 175 375px
B 100px 2 700 × 2/4 = 350 450px
C 0 1 700 × 1/4 = 175 175px

剩余 = 1000 − (200+100+0) = 700,Σgrow = 4。三个数加起来 1000,对得上。

所以那个”grow 按比例分宽度”的直觉,只在所有 basis 都为 0 的时候成立。而 flex: 1 恰好就是这个条件——flex: 1 展开是 flex: 1 1 0%。

算例二:flex: 1 和 flex: auto

这两个缩写的差别只在 basis:

flex: 1;      /* → flex-grow:1; flex-shrink:1; flex-basis:0%   */
flex: auto;   /* → flex-grow:1; flex-shrink:1; flex-basis:auto  */

取两个子项,内容自然宽度分别是 200px 和 600px,容器 1000px,都写 flex: 1:

  • flex: 1(basis 0%):剩余 = 1000 − 0 = 1000,各得 500 → 500 / 500。内容宽度完全不参与。
  • flex: auto(basis auto):basis 就是内容宽度 200 / 600,剩余 = 1000 − 800 = 200,各得 100 → 300 / 700。内容宽的那一侧结果也宽。

同一个容器、同一个 grow,结果差 200px。这就是”我明明设了 flex: 1 为什么两边不等宽”(或者反过来”为什么不等宽”)的全部原因。

收缩:同样按权重,但权重是 basis

溢出时 flex-shrink 也是加权分配的,权重是各自的 flex-basis,不是 grow 值。

容器 300px,两个子项 basis 分别是 300px 和 100px,shrink 都是 1,总宽 400px,溢出 100px:

A 承担: 100 × 300/400 = 75  →  300 − 75 = 225px
B 承担: 100 × 100/400 = 25  →  100 − 25 = 75px

不是各缩 50px。basis 大的承担得多,因为规范是按 basis 加权的。

而收缩有下限:不能小于 min-content。这一条经常表现为”shrink 设多大都不动”,是另一个问题,单独写在 flex 子项不肯缩小那篇里。

怎么记住

写 flex: 1 之前先回答一个问题:内容宽度要不要参与分配?

  • 不参与、纯粹按比例分整个容器 → flex: 1(basis 0%)
  • 参与、内容宽的应该更宽 → flex: auto(basis auto)
  • 固定尺寸不参与 → flex: 0 0 48px,三个值都写出来

这一个决定能解释掉九成”宽度跟我算的不一样”。剩下那一成,去看 min-width: auto。

← 返回技术笔记