填充和边界框中的flex-shrink因子如何?

假设我们有一个宽度为400px的flex容器。

这个容器里面有三个弹性项目:

:nth-child(1) { flex: 0 2 300px; } /* flex-grow, flex-shrink, flex-basis */ :nth-child(2) { flex: 0 1 200px; } :nth-child(3) { flex: 0 2 100px; } 

所以Flex项目的总宽度是600px,容器中的可用空间是-200px。

在这个问题的帮助下, 本文以及flexbox规范中 ,我学到了在flex项目中分配负空闲空间的基本公式:

步骤1

将每个缩小值乘以其基础并将它们相加:

 :nth-child(1) 2 * 300 = 600 :nth-child(2) 1 * 200 = 200 :nth-child(3) 2 * 100 = 200 

总计= 1000

第2步

将每个项目除以总数来确定收缩因子

 :nth-child(1) 600 / 1000 = .6 :nth-child(2) 200 / 1000 = .2 :nth-child(3) 200 / 1000 = .2 

第3步

乘以负空闲空间的收缩因子以确定从每个项目中移除的空间:

 :nth-child(1) .6 * -200px = -120px :nth-child(2) .2 * -200px = -40px :nth-child(3) .2 * -200px = -40px 

所以,每个弹性项目的计算大小应该是:

 :nth-child(1) 300px - 120px = 180px :nth-child(2) 200px - 40px = 160px :nth-child(3) 100px - 40px = 60px 

在Chrome,Firefox和IE11testing,数字检查。 计算完美。

 .flex { display: flex; width: 400px; height: 50px; margin: 0; padding: 0; list-style: none; text-align: center; } .flex li:nth-child(1) { flex: 0 2 300px; background: orange; } .flex li:nth-child(2) { flex: 0 1 200px; background: chartreuse; } .flex li:nth-child(3) { flex: 0 2 100px; background: aqua; } 
 <ul class="flex1 flex"> <li>180px</li> <li>160px</li> <li>60px</li> </ul> 

jsFiddle演示


问题

但是,当引入填充时,收缩结果是不同的。 当填充与box-sizing: border-box一起应用时,这会产生另一组数字。

在这里输入图像描述

涉及paddingbox-sizingflex-shrink计算是什么?

 .flex { display: flex; width: 400px; height: 50px; margin: 0; padding: 0; list-style: none; text-align: center; border-bottom: 1px solid #ccc; } .flex li:nth-child(1) { flex: 0 2 300px; background: orange; } .flex li:nth-child(2) { flex: 0 1 200px; background: chartreuse; } .flex li:nth-child(3) { flex: 0 2 100px; background: aqua; } .flex2 li { padding: 0 10px; } .flex3 li { padding: 0 10px; box-sizing: border-box; } 
 <ul class="flex1 flex"> <li>180px</li> <li>160px</li> <li>60px</li> </ul> <ul class="flex2 flex"> <li>144px</li> <li>148px</li> <li>48px</li> </ul> <ul class="flex3 flex"> <li>175.5px</li> <li>160px</li> <li>64.4px</li> </ul> 

jsFiddle演示

Flexbox将其定义为

对于线上的每个解冻项目,将其挠性收缩因子乘以其内部挠性基础尺寸 ,并将其记为缩放挠性收缩因子 。 find物品缩放弹性收缩率与线上所有解冻物品的缩放弹性收缩率之和的比率。 将项目的目标主尺寸设置为其柔性基础尺寸减去与该比例成比例的剩余空间的绝对值的一部分。

简化,冻结弹性项目是那些不能或不必弯曲了。 我将假设没有min-width限制和非零的收缩因子。 这样所有的弹性项目最初都是解冻的,并且在flex循环迭代一次之后,它们全部变为冻结。

内部柔性基础大小取决于CSS2UI定义的box-sizing的值

  • content-box :指定的宽度和高度(以及相应的最小/最大属性)分别适用于元素内容框的宽度和高度。 元素的填充和边框在指定的宽度和高度之外布置和绘制。

  • border-box :此元素的宽度和高度(以及相应的最小/最大属性)的长度和百分比值确定元素的边框。 也就是说,在元素上指定的任何填充或边框都是在此指定的widthheight内绘制和绘制的。 内容宽度和高度是通过从指定的宽度和高度属性中减去相应边的边框和填充宽度来计算的。 […]使用的值,例如通过getComputedStyle()公开的,也参考边框。

基本上,这意味着尺寸(宽度,弹性基地)有一个内部和外部的变种。 内部大小只包含内容,外部大小还包括填充和边框宽度。 样式表中指定的长度将用作box-sizing: content-box尺寸时的内部尺寸box-sizing: content-box ,或box-sizing: content-box的外部box-sizing: border-box 。 另一个可以通过添加或减去边框和填充宽度来计算。

忽略了很多细节,algorithm会是这样的

 let sumScaledShrinkFactors = 0, remainingFreeSpace = flexContainer.innerMainSize; for (let item of flexItems) { remainingFreeSpace -= item.outerFlexBasis; item.scaledShrinkFactor = item.innerFlexBasis * item.flexShrinkFactor; sumScaledShrinkFactors += item.scaledShrinkFactor; } for (let item of flexItems) { let ratio = item.scaledShrinkFactor / sumScaledShrinkFactors; item.innerWidth = item.innerFlexBasis + ratio * remainingFreeSpace; } 

没有填充,这是你解释

  (width) innerW │ padd │ outerW ───────┼──────┼─────── 300px * (1 + 2 / 1000px * -200px) = 180px │ 0px │ 180px 200px * (1 + 1 / 1000px * -200px) = 160px │ 0px │ 160px 100px * (1 + 2 / 1000px * -200px) = 60px │ 0px │ 60px ───────┼──────┼─────── 400px │ 0px │ 400px 

使用10px水平填充,可用空间减less了3 * 2 * 10px = 60px ,所以现在是-260px

  (width) innerW │ padd │ outerW ───────┼──────┼─────── 300px * (1 + 2 / 1000px * -260px) = 144px │ 20px │ 164px 200px * (1 + 1 / 1000px * -260px) = 148px │ 20px │ 168px 100px * (1 + 2 / 1000px * -260px) = 48px │ 20px │ 68px ───────┼──────┼─────── 340px │ 60px │ 400px 

当你使用box-sizing: border-box ,指定的flex基底是外部的,因此从它们中减去填充以计算内部的填充,即280px180px80px 。 然后缩放弹性收缩因子的总和变成2*280px + 180px + 2*80px = 900px 。 可用空间就像没有填充的情况,因为外部的柔性基底是相同的。 请注意,由getComputedStyle检索的width现在将是外部width ,所以在末尾添加填充。

  (width) innerW │ padd │ outerW ────────┼──────┼──────── 280px * (1 + 2 / 900px * -200px) ≈ 155.6px │ 20px │ 175.6px 180px * (1 + 1 / 900px * -200px) = 140.0px │ 20px │ 160.0px 80px * (1 + 2 / 900px * -200px) ≈ 44.4px │ 20px │ 64.4px ────────┼──────┼──────── 340.0px │ 60px │ 400.0px 

除了Oriol的回答(他现在已经更新)之外padding / border-box将会是

 280px * (1 + 2 / 900px * -200px) + 20px = 175.5px 180px * (1 + 1 / 900px * -200px) + 20px = 160px 80px * (1 + 2 / 900px * -200px) + 20px = 64.4px 

看起来填充首先从flex基础上移除,然后在实际计算之后再次添加回来,这有点padding