填充和边框中的 flex-shrink 因素如何? [英] How does flex-shrink factor in padding and border-box?

查看:20
本文介绍了填充和边框中的 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;}

所以弹性项目的总宽度为 600px,容器中的可用空间为 -200px.

当涉及paddingbox-sizing时,flex-shrink的计算是什么?

.flex {显示:弹性;宽度:400px;高度:50px;边距:0;填充:0;列表样式:无;文本对齐:居中;边框底部:1px 实心 #ccc;}.flex li:nth-child(1) {弹性:0 2 300px;背景:橙色;}.flex li:nth-child(2) {弹性:0 1 200px;背景:黄绿色;}.flex li:nth-child(3) {弹性:0 2 100px;背景:水色;}.flex2李{填充:0 10px;}.flex3 里 {填充:0 10px;box-sizing: 边框框;}

    <li>180px</li><li>160px</li><li>60px</li>
<ul class="flex2 flex"><li>144px</li><li>148px</li><li>48px</li><ul class="flex3 flex"><li>175.5px</li><li>160px</li><li>64.4px</li>

jsFiddle 演示

解决方案

Flexbox 将其定义为

<块引用>

对于生产线上的每个未冻结项目,乘以它的弹性收缩系数通过其内部 flex 基本尺寸,并将其记为 缩放弹性收缩系数.查找 item 的 缩放 flex 收缩的比率因子缩放的弹性收缩因子之和 所有解冻物品就行.将项目的目标主要尺寸设置为它的 flex 基本尺寸减去绝对值的一小部分剩余可用空间与比例成正比.

简化、冻结的 flex 项目是那些不能或不必再被 flex 的项目.我将假设没有 min-width 限制和非零弹性收缩系数.通过这种方式,所有 flex 项目最初都被解冻,并且在 flex 循环的一次迭代后它们都会被冻结.

内部 flex 基础大小取决于 box-sizing,CSS2UI 定义为

<块引用>
  • content-box:指定的宽度和高度(以及各自的最小/最大属性)分别应用于元素的内容框.元素的内边距和边框是在指定的宽度和高度之外布置和绘制.

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

基本上,这意味着尺寸(宽度、弹性底座)具有内部和外部变体.内部尺寸仅包括内容,外部尺寸还包括填充和边框宽度.在样式表中指定的长度将用作 box-sizing: content-box 的内部尺寸,或用作 box-sizing: border-box<的外部尺寸/代码>.另一个可以通过加减边框和填充宽度来计算.

忽略很多细节,算法将类似于

让 sumScaledShrinkFactors = 0,剩余自由空间 = flexContainer.innerMainSize;for (let item of flexItems) {剩余可用空间 -= item.outerFlexBasis;item.scaledShrinkFactor = item.innerFlexBasis * item.flexShrinkFactor;sumScaledShrinkFactors += item.scaledShrinkFactor;}for (let item of flexItems) {让比率 = item.scaledShrinkFactor/sumScaledShrinkFactors;item.innerWidth = item.innerFlexBasis + 比例 * 剩余可用空间;}

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

(宽度)内W │ 填充│ 外W────────┼────────┼────────300px * (1 + 2/1000px * -200px) = 180px │ 0px │ 180px200px * (1 + 1/1000px * -200px) = 160px │ 0px │ 160px100px * (1 + 2/1000px * -200px) = 60px │ 0px │ 60px────────┼────────┼────────400px │ 0px │ 400px

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

(宽度)内W │ 填充│ 外W────────┼────────┼────────300px * (1 + 2/1000px * -260px) = 144px │ 20px │ 164px200px * (1 + 1/1000px * -260px) = 148px │ 20px │ 168px100px * (1 + 2/1000px * -260px) = 48px │ 20px │ 68px────────┼────────┼────────340px │ 60px │ 400px

当你使用box-sizing:border-box时,指定的flex base是外边的,所以从它们中减去padding来计算内边距,也就是280px180px80px.那么缩放后的伸缩系数的总和变成 2*280px + 180px + 2*80px = 900px.可用空间就像没有填充的情况一样,因为外部 flex bases 是相同的.请注意,由 getComputedStyle 检索到的 width 现在将是外部的,因此在末尾添加了填充.

(宽度)内W │ 填充│ 外W────────┼────────┼────────280px * (1 + 2/900px * -200px) ≈ 155.6px │ 20px │ 175.6px180px * (1 + 1/900px * -200px) = 140.0px │ 20px │ 160.0px80px * (1 + 2/900px * -200px) ≈ 44.4px │ 20px │ 64.4px────────┼────────┼────────340.0px │ 60px │ 400.0px

Let's say we have a flex container with a width of 400px.

Inside this container are three flex items:

: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; }

So the total width of flex items is 600px and the free space in the container is -200px.

With help from this question, this article, and the flexbox spec, I've learned the basic formula for distributing negative free space among flex items:

Step 1

Multiply each shrink value by its basis and add them all together:

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

TOTAL = 1000

Step 2

Divide each item above by the total to determine the shrink factor:

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

Step 3

Multiply the shrink factor by the negative free space to determine the space removed from each item:

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

So, the computed size of each flex item should be:

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

Tested in Chrome, Firefox and IE11, the numbers check out. The calculation works perfectly.

.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


The Problem

When padding is introduced, however, the shrink results are different. When padding is applied along with box-sizing: border-box, this results in yet another set of numbers.

What's the flex-shrink calculation when padding and box-sizing are involved?

.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 defines this as

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.

Simplifying, frozen flex items are those which can't or don't have to be flexed anymore. I will assume no min-width restrictions and non-zero flex shrink factors. This way all flex items are initially unfrozen and they all become frozen after only one iteration of the flex loop.

The inner flex base size depends on the value of box-sizing, defined by CSS2UI as

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

Basically, that means that sizes (widths, flex bases) have an inner an an outer variant. The inner size includes only the content, the outer one also includes paddings and border widths. The length specified in the stylesheet will be used as the inner size in case of box-sizing: content-box, or as the outer one in case of box-sizing: border-box. The other can be calculated by adding or subtracting border and padding widths.

Neglecting lots of details, the algorithm would be something like

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;
}

With no paddings, it's as you explain

                                   (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

With 10px horizontal paddings, the available space is reduced by 3 * 2 * 10px = 60px, so now it's -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

When you use box-sizing: border-box, the specified flex bases are the outer ones, so the paddings are subtracted from them to calculate the inner ones, which are 280px, 180px, 80px. Then the sum of the scaled flex shrink factors becomes 2*280px + 180px + 2*80px = 900px. The available space is like in the case with no padding, because the outer flex bases are the same. Note the width retrieved by getComputedStyle will now be the outer one, so paddings are added back at the end.

                                                    (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

这篇关于填充和边框中的 flex-shrink 因素如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆