flex布局中flex-grow与flex-shrink的详细计算⽅式
flex-grow 的计算⽅式
flex-grow 属性决定了⽗元素在空间分配⽅向上还有剩余空间时,如何分配这些剩余空间。其值为⼀个权重(也称扩张因⼦),默认为
0(纯数值,⽆单位),剩余空间将会按照这个权重来分配。
⽐如剩余空间为 x,三个元素的 flex-grow 分别为 a,b,c。设 sum 为 a + b + c。那么三个元素将得到剩余空间分别是 x * a / sum, x * b / sum, x * c / sum,是为权重也。
举个例⼦:
⽗元素宽度 500px,三个⼦元素的 width 分别为 100px,150px,100px。
于是剩余空间为 150px
三个元素的 flex-grow 分别是 1,2,3,于是 sum 为 6
则三个元素所得到的多余空间分别是:
150 * 1 / 6 = 25px
150 * 2 / 6 = 50px
150 * 3 / 6 = 75px
三个元素最终的宽度分别为 125px,200px,175px。
100px + 25px = 125px
150px + 50px = 200px
100px + 75px = 175px
然⽽!不⽌这些,还有⼀种情况:
当所有元素的 flex-grow 之和⼩于 1 的时候(注意是 1,也就是说每个元素的 flex-grow 都是⼀个⼩数如 0.2 这样的),上⾯式⼦中的sum 将会使⽤ 1 来参与计算,⽽不论它们的和是多少。也就是说,当所有的元素的 flex-grow 之和⼩于 1 的时候,剩余空间不会全部分配给各个元素。
实际上⽤来分配的空间是 sum(flex-grow) / 1 * 剩余空间,这些⽤来分配的空间依然是按 flex-grow 的
⽐例来分配。
还是上⾯⼀个例⼦,但是三个元素的 flex-grow 分别是 0.1,0.2,0.3,那么计算公式将变成下⾯这样:
150 * 0.1 / 1 = 15px
150 * 0.2 / 1 = 30px
150 * 0.3 / 1 = 45px
150px - 15px - 30px - 45px = 60px,即还有 60px 没有分配给任何⼦元素。
三个元素的最终宽度分别为:
100px + 15px = 115px
150px + 30px = 180px
100px + 45px = 145px
如上所述即是 flex-grow 的计算⽅式。
另外,flex-grow 还会受到 max-width 的影响。如果最终 grow 后的结果⼤于 max-width 指定的值,max-width 的值将会优先使⽤。同样会导致⽗元素有部分剩余空间没有分配。
真实场景:
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
<style>
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
flex: 1 2 300px;
background: red;
}
.right {
flex: 2 1 200px;
background: blue;
}
</style>
剩余的空间:600 - (300 + 200) = 100。
⼦元素的 flex-grow 的值分别为 1,2, 剩余空间⽤3等分来分
100 / 3 = 33.3333333
所以 left = 300 + 1 * 33.33 = 333.33
right = 200 + 2 * 33.33 = 266.67
flex-shrink 的计算⽅式
既然可以在空间有多余时把多余空间分配给各个⼦元素,当然也可以在空间不够时让各个⼦元素收缩以适应有限的空间了。
这就是 flex-shrink 属性的作⽤。
你可能会觉得 flex-shrink 的计算⽅式跟 flex-grow 很类似,然⽽事情并没有这么简单。
flex-shrink 属性定义空间不够时各个元素如何收缩。其值默认为 1。很多⽂章对此基本是⼀笔带过:“flex-shrink 属性定义了元素的收缩系数”,根本就不说它具体是怎么计算的。
flex-shrink 定义的仅仅只是元素宽度变⼩的⼀个权重分量。
每个元素具体收缩多少,还有另⼀个重要因素,即它本⾝的宽度。
举个例⼦:
⽗元素 500px。三个⼦元素分别设置为 150px,200px,300px。
三个⼦元素的 flex-shrink 的值分别为 1,2,3。
⾸先,计算⼦元素溢出多少:150 + 200 + 300 - 500 = -150px。
那这 -150px 将由三个元素的分别收缩⼀定的量来弥补。
具体的计算⽅式为:每个元素收缩的权重为其 flex-shrink 乘以其宽度。
所以总权重为 1 * 150 + 2 * 200 + 3 * 300 = 1450
三个元素分别收缩:
150 * 1(flex-shrink) * 150(width) / 1450 = -15.5
150 * 2(flex-shrink) * 200(width) / 1450 = -41.4
150 * 3(flex-shrink) * 300(width) / 1450 = -93.1
三个元素的最终宽度分别为:
150 - 15.5 = 134.5
200 - 41.4 = 158.6
300 - 93.1 = 206.9
同样,当所有元素的 flex-shrink 之和⼩于 1 时,计算⽅式也会有所不同:
此时,并不会收缩所有的空间,⽽只会收缩 flex-shrink 之和相对于 1 的⽐例的空间。
还是上⾯的例⼦,但是 flex-shrink 分别改为 0.1,0.2,0.3。
于是总权重为 145(正好缩⼩ 10 倍,略去计算公式)。
三个元素收缩总和并不是 150px,⽽是只会收缩 150px 的 (0.1 + 0.2 + 0.3) / 1 即 60% 的空间:90px。每个元素收缩的空间为:
90 * 0.1(flex-shrink) * 150(width) / 145 = 9.31
90 * 0.2(flex-shrink) * 200(width) / 145 = 24.83
90 * 0.3(flex-shrink) * 300(width) / 145 = 55.86
三个元素的最终宽度分别为:
150 - 9.31 = 140.69
flex布局详细讲解
200 - 24.83 = 175.17
300 - 55.86 = 244.14
当然,类似 flex-grow,flex-shrink 也会受到 min-width 的影响。
真实场景:
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
<style>
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
flex: 1 2 500px;
background: red;
}
.right {
flex: 2 1 400px;
background: blue;
}
</style>
⼦元素的 flex-shrink 的值分别为 2,1
溢出:500+400 - 600 = 300。
总权重为 2 * 500+ 1 * 400 = 1400
两个元素分别收缩:
300 * 2(flex-shrink) * 500(width) / 1400= 214.28
300 * 1(flex-shrink) * 400(width) / 1400= 85.72
三个元素的最终宽度分别为:
500 - 214.28 = 285.72
400 - 85.72 = 314.28
总结
虽然上⾯的公式看起来很复杂,其实计算过程还是⽐较简单的:如果所有元素的 flex-grow/shrink 之和⼤于等于 1,则所有⼦元素的尺⼨⼀定会被调整到适应⽗元素的尺⼨(在不考虑 max/min-width/height 的前提下),⽽如果 flex-grow/shrink 之和⼩于 1,则只会 grow 或 shrink 所有元素 flex-grow/shrink 之和相对于 1 的⽐例。grow 时的每个元素的权重即为元素的 flex-grow 的值;shrink 时每个元素的权重则为元素 flex-shrink 乘以 width 后的值。