弹性盒
flex 布局是现在最常用的一种布局方式,而均匀分布、按比例分布等等也是我们最常见的一种需求。而 flex 这个属性恰恰能满足我们的日常需求。
属性讲解
flex-grow
flex-grow 属性定义了项目的放大比例,默认为 0,即如果存在剩余空间,也不放大。如果所有项目的 flex-grow 属性都为 1,则它们将等分剩余空间。
也就是说,如果我们的需求是要均匀分布几个盒子,那就可以不设宽度,然后设置 flex-grow 为 1 ,这样它们就会均匀地填充剩余空间。
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: 1;。但有个弊端,只考虑 flex-grow 的情况下,不适用于换行。
flex-shrink
flex-shrink 属性定义了项目的缩小比例,默认为 1,即如果空间不足,该项目将缩小。如果所有项目的 flex-shrink 属性都为 1,当空间不足时,都将等比例缩小。
目前这个属性我用的是比较少的,一般不改变,使用默认值。
flex-basis
flex-basis 属性定义了在分配多余空间之前,项目占据的主轴空间(宽度)。默认值为 auto,即项目的本来大小。
简单来说就是这个最初的空间分配,分配了之后,flex-grow 再去分配剩余空间。下面的两个例子都是在 flex-basis 为 auto 的情况下处理的。
初始有空间
当某个盒子初始有空间时,使用 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: 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>

例子
现在有一个需求,多个盒子均匀分布,每行 4 个盒子,超过了则换行,每个盒子的宽度一致。
这里用到了上面的三个属性,但有一个误区,认为 flex-grow和「」挂钩了,那就错了。如果 flex-grow 为 1,在同行中确实均匀分布了,但如果该行是最后一行,只有两个盒子,那将「均分」剩余空间,就会造成一个盒子占据了 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: 0 0 calc((100% - 3 * $gap) / 4) 是简写,意思是 flex-grow: 0、flex-shrink: 0、flex-basis: calc((100% - 3 * $gap) / 4)。
flex-grow: 0 是不分配剩余空间,目的是针对做后一行不满 4 个的情况。