<!DOCTYPE html>
<html lang="cmn-hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.test {
width: 600px;
height: 600px;
border: 1px solid black;
display: flex;
}
.test .content {
width: 200px;
height: 200px;
box-sizing: border-box;
border: 1px solid red;
}
.content.unique {
width: 400px;
flex-shrink: 3;
}
</style>
</head>
<body>
<div class="test">
<div class="content">1</div>
<div class="content">2</div>
<div class="content unique">3</div>
</div>
</body>
</html>
在这个环境下,先计算一下每个盒子压缩之后的宽度,首先,三个盒子的宽度比为 200:200:400,即 1:1:2,乘以其各自的 flex-shrink
,得到的比例为 1:1:6,所以超出的比例是按照 1:1:6的比例压缩的,容器宽度为 600,弹性项总宽度为 800,超出了 200,这 200 分成 1+1+6=8 份,每一份 25像素,1 号占一份,被压缩 25 像素,宽度为 200-25=175 像素,2 号占 1 份,被压缩 25 像素,也剩 175 像素,三号占 6 份,被压缩 150 像素,宽度为 400-150=250 像素
但最终结果却不尽如意,我们会发现这里每一个盒子和我们算出来的虽然大差不差,但总会有那么一丢丢误差。
如果我在控制台取消掉 box-sizing:border-box;
以及 border
属性之后,发现其结果又正常了。这里其实就是计算上的一个细节,在计算权重的时候,我们需要把盒子宽度的比值和其对应的 flex-shrink
乘起来,得到最终的权值,但这个盒子宽度的比值应该是盒子内容区宽度的比值,或者说是 content-box
的宽度,而非 border-box
的宽度。
在上面的例子中,由于有 1 像素的边框,所以盒子内容区宽度的比值应该是 198:198:398,乘以对应的 flex-shrink
应该是 198:198:1194,超出来的这 200 像素会按照这个比例被压缩,即第一个盒子压缩 (198/1590)*200, 剩下 175.09433962264150943396226415094 px
,第二个盒子也一样,第三个盒子被压缩 (1194/1590)*200,剩下 249.81132075471698113207547169811 px
,
读者可以看到,这已经很接近实际的数字了,但总会差那么一丁点,这实际上就是浏览器本身的问题了,因为不同浏览器其最终渲染效果也各不相同,主要的差异是对 CSS 中小数的处理,例如 chrome 中前两个盒子的宽度都是 175.09 px,第三个盒子为 249.83 px,这一点和上面 firefox 的数值就不一样,但这一丁点误差也并不会影响开发,读者只需要理解,在计算最终比值时所用到的宽度应该是 content-box
的,而非 border-box
。