css - flex-shrink 如何影响 padding 和 border-box?

标签 css flexbox

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

在这个容器里面是三个 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 question 的帮助下, this article , 和 flexbox spec ,我已经了解了在 flex 元素之间分配负自由空间的基本公式:

第一步

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

: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

因此,每个 flex 元素的计算大小应该是:

: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

当涉及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

最佳答案

Flexbox定义为

For every unfrozen item on the line, multiply its flex shrink factor by its inner flex base size, and note this as its scaled flex shrink factor. Find the ratio of the item’s scaled flex shrink factor to the sum of the scaled flex shrink factors of all unfrozen items on the line. Set the item’s target main size to its flex base size minus a fraction of the absolute value of the remaining free space proportional to the ratio.

简化、卡住的伸缩元素是那些不能或不必再伸缩的元素。我假设没有 min-width 限制和非零 flex 收缩系数。这样一来,所有 flex 元素最初都是解冻的,它们都在 flex 循环的一次迭代后全部卡住。

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

  • content-box: The specified width and height (and respective min/max properties) apply to the width and height respectively of the content box of the element. The padding and border of the element are laid out and drawn outside the specified width and height.

  • border-box: Length and percentages values for width and height (and respective min/max properties) on this element determine the border box of the element. That is, any padding or border specified on the element is laid out and drawn inside this specified width and height. The content width and height are calculated by subtracting the border and padding widths of the respective sides from the specified width and height properties. [...] Used values, as exposed for instance through getComputedStyle(), also refer to the border box.

基本上,这意味着尺寸(宽度、 flex 底座)有内部和外部变体。内部尺寸仅包括内容,外部尺寸还包括填充和边框宽度。在 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是最外面的,所以减去paddings来计算最里面的,就是280px180px80px。然后缩放的 flex 收缩因子的总和变为 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

关于css - flex-shrink 如何影响 padding 和 border-box?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34753491/

相关文章:

css - 如何使用 Bootstrap 声明列表?

html - 为什么默认情况下 html 元素不是 100% 高度?

css - 否则更改 angularjs Controller 内的 css 类名

html - Flex Layout、纵横比、固定宽度和动态宽度列

css - 如何让 Firefox 和 IE 在 flexbox 布局中正确呈现书写模式?

css - 如何对齐两个相邻的html元素之间的文本

html - 如何更改 jquery-mobile 中选择列表标题的字体大小?

css - 如何在 bool 玛级别组件中实现分词并设置左右等宽?

html - 无法显示 div 中间 html css

react-native - 带有 flex 1 的 ScrollView 使其不可滚动