深入CSS弹性布局计算原理:从flex-grow扩张到flex-shrink收缩

646 阅读5分钟

前言

在现代CSS布局中,Flexbox(弹性盒子)因其强大的对齐和空间分配能力,成为前端开发的核心工具之一。在Flex中可以设置非常多的属性,本文针对flex属性仔细介绍,慢慢介绍关于的它的所有细节。


flex属性解析

flex 是 CSS Flexbox 布局中的一个复合属性,它是三个子属性的复合: flex-growflex-shrink 和 flex-basis 。其中:

  1. flex-grow:定义项目在容器有剩余空间时的扩张比例。
  2. flex-shrink:定义项目在容器空间不足时的收缩比例。
  3. flex-basis:设置项目的初始基准尺寸(类似width,但优先级更高)。

它们的默认值分别是:0 1 auto(不扩张、可收缩、基准尺寸为内容大小)

比如我们在业务中常见的写法flex: 1 实际上是为这三个子属性指定以下值:

  • flex-grow: 1
  • flex-shrink: 1
  • flex-basis: auto

那么这些属性到底有什么意义呢?我们该如何设置呢?请看下文。



flex的核心特性:空间分配

接下来我为大家仔细介绍Flex布局的核心用法:空间分配。分为两种情况:剩余空间和不足空间。接下来我们通过结合两个案例的方式来进行讲解两种情况,


实战项目一:flex-grow的扩张计算

当 父容器大小 > 所有子元素的 flex-basis 总宽度 时,存在剩余空间,按 flex-grow 比例分配。

下面的代码主轴为横轴,flex-growflex-shrink 和 flex-basis 用户都自己指定了具体的值,请你思考一下,告诉我页面中的leftright的宽度具体是多少?

    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .container{
            width: 600px;
            height: 300px;
            display: flex;
        }
        .left {
            flex: 1 2 300px;
            width: 300px;
            background-color: red;
        }
        .right {
            flex: 2 1 200px;
            width: 200px;
            background-color: blue;
        }
    </style>

<body>
    <div class="container">
        <!-- FFC 弹性格式化上下文 -->
        <div class="left"></div>
        <div class="right"></div>
    </div>
</body>

下面,我们通过页面检查查看结果:left宽度为333.33px,right宽度为267.77px

屏幕截图 2025-06-10 180808.png

接下来我们仔细分析是如何得到这个结果的

父元素的width是600px,两个子元素都都设置了flex-basis属性,其中,left的为300px,right的为200px。我们发现 600px > 300px+200px ,说明容器大小 > 所有项目的 flex-basis 总宽度,触发flex-grow的扩张运算。


计算步骤1:
计算剩余空间

剩余空间 = 父容器宽度 - (子元素1flex-basis + 子元素2flex-basis + ...)

案例中剩余空间为
600px - 300px - 200px = 100px


计算步骤2:
按flew-grow比例分配空间

子元素得到的空间 =  剩余空间 * (子元素的flex-grow / 总flex-grow)

案例中子元素得到的空间
left: (100px * 1/3) ≈ 33.33px
right: (100px * 2/3) ≈ 67.77px


计算步骤3:
得到最终宽度

子元素最终宽度 = flex-basis + 子元素得到的空间

所以这里得到最终宽度分别为:

left : 300px + 33.33px ≈ 333.33px
right : 200px + 67.77px ≈ 267.77px



实战项目二:flex-shrink的收缩计算

当 容器大小 < 所有项目的 flex-basis 总宽度 时,空间不足,按 flex-shrink 加权压缩。

下面的代码主轴为横轴,flex-growflex-shrink 和 flex-basis 用户都自己指定了具体的值,请你思考一下,告诉我页面中的leftright的宽度具体是多少?


    <style>
        *{
            margin: 0;
            padding: 0;
        }

        .container{
            display: flex;
            width: 600px;
            height: 300px;
        }
        .left{
            flex: 1 2 500px;
            background-color: red;
        }

        .right{
            flex: 2 1 400px;
            background-color: blue;
        }
    </style>

<body>
    <div class="container">
        <div class="left"></div>
        <div class="right"></div>
    </div>
</body>

下面,我们通过页面检查查看结果:left宽度为285.717px,right宽度为314.283px

aaaaaa.png

接下来我们仔细分析是如何得到这个结果的

父元素的width是600px,两个子元素都都设置了flex-basis属性,left的为500px,right的为400px。我们发现 600px < 500px+400px ,说明容器大小 < 所有项目的 flex-basis 总宽度,所以按 flex-shrink 加权压缩。


计算步骤1:
计算不足空间

不足空间 = (子元素1flex-basis + 子元素2flex-basis + ...) - 容器宽度

案例中不足空间为
(400px + 500px) - 600px = 300px


计算步骤2:
计算总权重

总权重 = (子元素1flex-basis * 子元素1flex-shrink) + (子元素2flex-basis * 子元素2flex-shrink)....

案例中总权重为
(500px * 2) + (400px * 1) = 1400px


计算步骤3:计算收缩比例

子元素收缩比例 = (子元素的flex-basis * 子元素的flex-shrink) / 总权重

案例中子元素的收缩比例为
left: (500px * 2) / 1400px = 5/7
right:(400px * 1) / 1400px = 2/7


计算步骤四:计算最终宽度

子元素的最终宽度 = 子元素的flex-basis - (收缩比例) * 不足空间

案例中子元素的最终宽度为
left: 500px - 5/7 * 300px = 285.717px
right: 400px - 2/7 * 300px = 314.283px



注意事项

在上面两个案例中,我们需要注意:

  1. flex-basis 的优先级

    • 在主轴方向上,flex-basis 会覆盖 width(除非 flex-basis: auto)。
    • 设置 flex-basis: 0 会让项目完全依赖 flex-grow 分配空间(忽略内容宽度)。
  2. flex-shrink 的特殊性

    • 收缩计算时,flex-shrink 会乘以 flex-basis 作为权重,因此大尺寸项目收缩更多。
    • 若 flex-shrink: 0,项目拒绝收缩,可能导致溢出容器。
  3. 最小尺寸限制

    • 即使计算后宽度为负,项目也不会小于其 min-content(除非显式设置 min-width)。

最后,给出两种方式的差异总结:

flex-grow vs. flex-shrink 的核心差异

特性flex-grow (扩张)flex-shrink (收缩)
触发条件容器有剩余空间时容器空间不足时
计算逻辑按比例分配剩余空间按 flex-shrink × flex-basis 加权压缩
默认值0(不扩张)1(允许收缩)
权重影响仅依赖 flex-grow 值受 flex-shrink 和 flex-basis 共同影响
极端情况若所有项目 flex-grow: 0,剩余空间留白若所有项目 flex-shrink: 0,可能导致容器溢出