如何在填充和边框中使用flex-shrink因子?

时间:2016-01-12 20:48:23

标签: css css3 flexbox

假设我们有一个宽度为400像素的弹性容器。

此容器内有三个弹性项目:

: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。

this questionthis articleflexbox spec的帮助下,我学会了在弹性项目中分配负空闲空间的基本公式:

第1步

将每个收缩值乘以其基础并将它们全部加在一起:

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

TOTAL = 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和IE11中测试过这些数字。计算效果很好。

.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 demo

问题

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

enter image description here

涉及flex-shrinkpaddingbox-sizing计算的内容是什么?

.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 demo

2 个答案:

答案 0 :(得分:20)

Flexbox将此定义为

  

对于生产线上每个未冻结的项目,乘以其弹性收缩系数   通过其内部flex base size,并注意这是 缩放的flex   收缩因子 。找出项目的scaled flex shrink factor与所有scaled flex shrink factors之和的比率   解冻线上的物品。将项目的target main size设置为   它的flex base size减去绝对值的一小部分   remaining free space与比例成正比。

简化冷冻弹性物品是指不再需要或不必弯曲的物品。我将假设没有min-width限制和非零弹性收缩因子。这样,所有弹性项目最初都会解冻,并且只需在flex循环的一次迭代后就会冻结。

内部flex基本大小取决于box-sizing的值,由CSS2UI定义为

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

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

  •   

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

忽略大量细节,算法类似于

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水平填充,可用空间减少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基础是外部的,因此从它们中减去填充以计算内部的填充,280px180px,{{ 1}}。然后,缩放的弹性收缩因子的总和变为80px。可用空间类似于没有填充的情况,因为外部柔性基座是相同的。请注意2*280px + 180px + 2*80px = 900px检索到的width现在将是外部getComputedStyle,因此最后会添加填充。

                                                    (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

答案 1 :(得分:6)

除了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

看起来填充首先从弹性基础上移除,然后在实际计算之后再次添加回来,这使得有点有些意义,因为这是{{1 }}