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

Mic*_*l_B 28 css css3 flexbox

假设我们有一个宽度为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; }
Run Code Online (Sandbox Code Playgroud)

因此,flex项的总宽度为600px,容器中的可用空间为-200px.

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

步骤1

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

:nth-child(1)  2 * 300 = 600
:nth-child(2)  1 * 200 = 200
:nth-child(3)  2 * 100 = 200
Run Code Online (Sandbox Code Playgroud)

总计= 1000

第2步

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

:nth-child(1)  600 / 1000 = .6
:nth-child(2)  200 / 1000 = .2
:nth-child(3)  200 / 1000 = .2
Run Code Online (Sandbox Code Playgroud)

第3步

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

:nth-child(1)  .6 * -200px = -120px
:nth-child(2)  .2 * -200px =  -40px
:nth-child(3)  .2 * -200px =  -40px
Run Code Online (Sandbox Code Playgroud)

因此,每个弹性项的计算大小应为:

:nth-child(1)  300px - 120px = 180px
:nth-child(2)  200px -  40px = 160px
:nth-child(3)  100px -  40px =  60px
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)
<ul class="flex1 flex">
  <li>180px</li>
  <li>160px</li>
  <li>60px</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

jsFiddle演示


问题

然而,当引入填充时,收缩结果是不同的.当同时应用填充时box-sizing: border-box,这会导致另一组数字.

在此输入图像描述

什么flex-shrink时候paddingbox-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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

jsFiddle演示

Ori*_*iol 23

Flexbox将此定义为

对于生产线上每个未冻结的项目,将其挠曲收缩系数乘以其内部柔性基础尺寸,并将其注意为其缩放的柔性收缩系数.找到该项目的比例缩放的弹性收缩系数的总和缩放弯曲收缩因素,该行的全部解冻项目.将项目的目标主要大小设置为其弹性基础大小减去与该比率成比例的剩余可用空间的绝对值的 一部分.

简化的冷冻弹性物品是那些不能或不必弯曲的物品.我将假设没有min-width限制和非零弹性收缩因子.这样,所有弹性项目最初都会解冻,并且在仅仅一次Flex循环迭代后它们都会冻结.

内部flex基本大小取决于box-sizingCSS2UI定义的值

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

  • border-box:此元素的宽度和高度(以及相应的最小/最大属性)的长度和百分比值确定元素的边框.也就是说,在元素上指定的任何填充或边框布局和绘制这里面指定的widthheight.通过从指定的宽度和高度属性中减去各边的边框和填充宽度来计算内容宽度和高度.[...]使用的值,例如通过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;
}
Run Code Online (Sandbox Code Playgroud)

没有填充,就像你解释的那样

                                   (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
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

当您使用box-sizing: border-box,指定柔性基地是外部的,所以补白是从他们减去计算在内的,它们是280px,180px,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
Run Code Online (Sandbox Code Playgroud)

  • CSSWG刚刚(我刚刚参加CSSWG会议)决定尝试更改规范以使flexing考虑到box-sizing,以匹配OP的直觉.我们希望它与Web兼容,并且将获得实现以试用它并查看它是否有效. (6认同)

LGS*_*Son 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
Run Code Online (Sandbox Code Playgroud)

它出现的填充首先从柔性基础删除,然后再次添加,实际计算后,使那种某种意义上,因为这是与发生了什么padding.