弹性盒均匀布局

flex-grow,flex-shrink,flex-basis

Posted by My on March 12, 2025

弹性盒

flex 布局是现在最常用的一种布局方式,而均匀分布、按比例分布等等也是我们最常见的一种需求。而 flex 这个属性恰恰能满足我们的日常需求。

属性讲解

flex-grow

flex-grow 属性定义了项目的放大比例,默认为 0,即如果存在剩余空间,也不放大。如果所有项目的 flex-grow 属性都为 1,则它们将等分剩余空间。

也就是说,如果我们的需求是要均匀分布几个盒子,那就可以不设宽度,然后设置 flex-grow1 ,这样它们就会均匀地填充剩余空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
  <div class="main mt30">
    <div class="item" style="background: khaki;"></div>
    <div class="item" style="background: pink;"></div>
    <div class="item" style="background: skyblue;"></div>
  </div>
</template>

<style lang="scss" scoped>
.main {
  display: flex;
  height: 200px;
  .item {
    flex-grow: 1; //平均分配剩余空间
    height: 100%;
  }
}
</style>

flex-grow.png

这是最常用的,简化写法为 flex: 1;。但有个弊端,只考虑 flex-grow 的情况下,不适用于换行。

flex-shrink

flex-shrink 属性定义了项目的缩小比例,默认为 1,即如果空间不足,该项目将缩小。如果所有项目的 flex-shrink 属性都为 1,当空间不足时,都将等比例缩小。

目前这个属性我用的是比较少的,一般不改变,使用默认值。

flex-basis

flex-basis 属性定义了在分配多余空间之前,项目占据的主轴空间(宽度)。默认值为 auto,即项目的本来大小。

简单来说就是这个最初的空间分配,分配了之后,flex-grow 再去分配剩余空间。下面的两个例子都是在 flex-basisauto 的情况下处理的。

初始有空间

当某个盒子初始有空间时,使用 flex-grow 并不能使所有的盒子的宽度是 「一致」的,因为是分配剩余空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
  <div class="main mt30">
    <div class="item" style="background: skyblue;">
      你好哦,今天是元气满满的一天!
    </div>
    <div class="item" style="background: pink;"></div>
    <div class="item" style="background: khaki;"></div>
  </div>
</template>

<style lang="scss" scoped>
.main {
  display: flex;
  height: 200px;
  .item {
    flex-grow: 1;
    height: 100%;
  }
}
</style>

第一个 div 有了内容,也就是说初始是有空间的,因此 flex-grow 并不能使所有的盒子的宽度是 「一致」的。但是分配的空间是均匀的。

flex-grow-basic.png

如上图,盒子的宽度并不相等,但是分配的空间是均匀的。

初始没有空间

没有初始空间,就是默认的情况,盒子里无内容,就和 flex-grow: 1; 一样的效果。

设置初始空间

设置 flex-basis 可以指定初始空间,然后 flex-grow 再去分配剩余空间,就可以做到均匀分配了,以上的「均匀分配」的例子中,盒子都是没有内容的,所以可认为初始空间是 0。因此,设置 flex-basis: 0; 后,分配的空间就是均匀的了。

1
2
3
4
5
6
7
8
9
10
11
<style lang="scss" scoped>
.main {
  display: flex;
  height: 200px;
  .item {
    flex-grow: 1;
    flex-basis: 0; //设置初始空间为0
    height: 100%;
  }
}
</style>

flex-grow-basic1.png

例子

现在有一个需求,多个盒子均匀分布,每行 4 个盒子,超过了则换行,每个盒子的宽度一致。

这里用到了上面的三个属性,但有一个误区,认为 flex-grow和「」挂钩了,那就错了。如果 flex-grow1,在同行中确实均匀分布了,但如果该行是最后一行,只有两个盒子,那将「均分」剩余空间,就会造成一个盒子占据了 2 个位置。

因此,重心应该放在 flex-basis上,分配初始空间,然后不分配剩余空间。这种操作类似于设置百分比。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
  <div class="main mt30">
    <div class="item" style="background: skyblue"></div>
    <div class="item" style="background: pink"></div>
    <div class="item" style="background: khaki"></div>
    <div class="item" style="background: khaki"></div>
    <div class="item" style="background: khaki"></div>
    <div class="item" style="background: khaki"></div>
    <div class="item" style="background: khaki"></div>
    <div class="item" style="background: khaki"></div>
    <div class="item" style="background: khaki"></div>
  </div>
</template>

<style lang="scss" scoped>
.main {
  $gap: 15px;
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  .item {
    height: 100px;
    border-radius: 10px;
    flex: 0 0 calc((100% - 3 * $gap) / 4); //分配初始空间,不分配剩余空间
  }
}
</style>

flex-basis.png

这里 flex: 0 0 calc((100% - 3 * $gap) / 4) 是简写,意思是 flex-grow: 0flex-shrink: 0flex-basis: calc((100% - 3 * $gap) / 4)

flex-grow: 0 是不分配剩余空间,目的是针对做后一行不满 4 个的情况。