先记住这个答案
在单行 flex 容器中,可以先用各项基础尺寸之和减去可用宽度,得到需要分摊的负空间;再用每项的 flex-shrink * flex-basis 算权重,按比例初步分摊。这个简化算法假设没有内外边距和尺寸约束。实际布局还要检查最小、最大尺寸;某项触及边界后,浏览器会对其余项重新分配负空间。
- 收缩按因子和基准尺寸加权
flex-basis越大的项承担更多收缩- 自动最小尺寸可能限制收缩
- 所有项的
flex-shrink都是 0 就直接溢出
用具体数字走一遍公式
假设容器宽 300px,里面有 A 和 B 两个子项。A 的 flex-basis 是 200px、flex-shrink 是 2;B 的 flex-basis 是 200px、flex-shrink 是 1。总 flex-basis 是 400px,溢出 100px。
/* 容器 300px,A 和 B 各 200px,溢出 100px */
.container { display: flex; width: 300px; }
/* A 权重 = 2 × 200 = 400;移除自动最小宽度干扰 */
.item-a { flex: 0 2 200px; min-width: 0; }
/* B 权重 = 1 × 200 = 200 */
.item-b { flex: 0 1 200px; min-width: 0; }
/* 总权重 = 400 + 200 = 600 */
/* A 收缩 = 100 × (400/600) ≈ 66.7px → 最终 133.3px */
/* B 收缩 = 100 × (200/600) ≈ 33.3px → 最终 166.7px */A 的权重是 400,B 是 200,总权重 600。A 分摊 100 * 400/600 约等于 66.7px,最终宽度约 133.3px;B 分摊约 33.3px,最终约 166.7px。两项加起来正好 300px,刚好填满容器。
注意 A 和 B 的 flex-basis 一样大,但 A 的 flex-shrink 是 B 的两倍,所以 A 承担的收缩量也是 B 的两倍。如果 flex-basis 不同,权重还会受它影响。
为什么 flex-basis 也参与权重
flex-shrink 的设计思路是按比例收缩,不是按固定像素收缩。一个 flex-basis 为 600px 的大区块和一个 100px 的小图标,即使 flex-shrink 都是 1,大区块的权重是小图标的 6 倍,收缩量也是 6 倍。这样小图标不会被压得不可辨认。
flex-basis 的情况CSS.container { display: flex; width: 500px; }
/* C 权重 = 1 × 600 = 600 */
.content { flex: 0 1 600px; }
/* D 权重 = 1 × 100 = 100 */
.icon { flex: 0 1 100px; }
/* 溢出 200px,总权重 700 */
/* C 收缩 = 200 × 600/700 ≈ 171px → 最终约 429px */
/* D 收缩 = 200 × 100/700 ≈ 29px → 最终约 71px */flex-shrink 相同的情况下,flex-basis 越大的项收缩越多。所以说「flex-shrink 决定收缩比例」并不完全准确,准确的说法是 flex-shrink * flex-basis 共同决定。
容易答错的地方
- 以为
flex-shrink就是收缩的像素数 flex-shrink: 2不是说收缩 2px,也不是说收缩量一定是flex-shrink: 1的两倍。实际收缩量取决于溢出量、自身flex-basis、以及其他子项的权重。只看flex-shrink本身的数值没有意义,要放到公式里才能算出结果。- 忘了
min-width的兜底 - 公式算出来需要继续收缩,但若子项包含不可断的长文本,最小内容宽度可能达到 180px。对于非滚动容器的 flex 项,默认的
min-width: auto可能让它无法缩到 180px 以下。这时浏览器会重新分配负空间;其余项也无法再缩时才会溢出。排查时要同时检查最小尺寸和内容能否换行。
面试官还会怎么问?
flex-shrink 和 flex-grow 的计算方式一样吗?
思路一样,都是按权重分配。flex-grow 是分配剩余空间,权重就是 flex-grow 值本身;flex-shrink 是分摊溢出量,权重是 flex-shrink * flex-basis。区别在于 flex-shrink 多乘了一个 flex-basis,这是为了让大元素承担更多收缩。
三个子项的 flex-shrink 分别是 1、2、3,哪个最终最宽?
不一定。还要看各自的 flex-basis。如果三项 flex-basis 一样,那 flex-shrink 最小的最宽;但如果 flex-shrink: 3 的那项 flex-basis 特别小,它的权重反而可能最低,收缩最少。
把所有子项的 flex-shrink 都设成 0 会怎样?
所有子项都拒绝收缩,总 flex-basis 超过容器宽度时就会溢出。如果容器没有设 overflow: hidden 或 overflow: auto,多出来的部分会直接超出容器边界。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。