【问题标题】:How does flex-shrink factor in padding and border-box?flex-shrink 如何影响填充和边框?
【发布时间】:2016-04-17 15:33:32
【问题描述】:

假设我们有一个宽度为 400 像素的 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。

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

第 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 和 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 一起应用时,这会产生另一组数字。

当涉及paddingbox-sizing 时,flex-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 demo

【问题讨论】:

    标签: css flexbox


    【解决方案1】:

    Flexbox 将其定义为

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

    简化的、冻结的弹性项目是那些不能或不必再弯曲的项目。我将假设没有min-width 限制和非零弹性收缩系数。这样一来,所有的 flex 项目最初都是解冻的,并且在 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 bases是外部的,所以从它们中减去填充来计算内部的,它们是280px180px80px。然后缩放的弹性收缩因子的总和变为2*280px + 180px + 2*80px = 900px。可用空间就像没有填充的情况一样,因为外部弹性底座是相同的。请注意,getComputedStyle 检索到的 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
    

    【讨论】:

    • CSSWG 刚刚(字面意思是现在,在我参加的 CSSWG 会议上)决定尝试更改规范以使 flexing 考虑 box-sizing,以符合 OP 的直觉。我们希望它是网络兼容的,并且会得到实现来试用它,看看它是否有效。
    • @Xanthir 我猜它毕竟没有改变?
    【解决方案2】:

    除了 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-basis 中删除,然后又重新添加回来,这使得 有点有些意义,因为 padding 会发生这种情况.

    【讨论】:

    • 啊,当然。我忘了在末尾添加20px,所以数字不匹配。
    • @Oriol 我也做了一段时间 :) ...但是让我花费最多时间的事情是找出 900px,我终于看到需要乘以每个收缩值有它的基础,然后再全部添加,(2 * 280) + (1 * 180) + (2 * 80) = 900px.
    猜你喜欢
    • 1970-01-01
    • 2014-05-23
    • 2013-01-19
    • 2023-03-07
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    相关资源
    最近更新 更多