32

在下面的代码片段中,第一行有两个带有flex-grow: 1. 正如预期的那样,每个 div 占据了 50% 的屏幕。

在向左 div 添加填充时,情况不再如此。有人可以解释为什么吗?

body > div {
  height: 50px;
  display: flex;
}
body > div > div {
  flex: 1;
  box-sizing: border-box;
}
#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
}
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

4

5 回答 5

37

计算在规范中定义。

带有填充的弹性项目的大小,由弹性盒规范flex-grow中的计算确定。

这些计算类似于使用 padding 和flex-shrink.

坦率地说,数学是相当技术性的,并不是世界上最容易理解的东西。

但是如果你想进入它,这里有详细信息:


例子

以下是希望使行为更加清晰的示例。

注意: 请记住,这flex-grow不是直接确定弹性项目长度的工具。它是一种在弹性项目之间分配容器空间的工具。该flex-basis属性设置弹性项目的初始主尺寸。如果flex-grow与 一起使用flex-basis,则问题中的问题得到解决(参见下面的示例 #4)。

示例 #1

在您拥有的块容器中box-sizing: border-box,无论填充如何,您的代码中的框都将均匀呈现。

body > div {
  height: 50px;
  /* display: flex; */
  font-size: 0; /* remove inline block whitespace */
}
body > div > div {
  /* flex: 1; */
  box-sizing: border-box;
  height: 50px;
  display: inline-block;
  width: 50%;
}
#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

jsFiddle 演示


示例 #2

flex 容器中,你有box-sizing: border-box,并且widthorflex-basis用于计算长度,无论填充如何,框都会均匀渲染。

body > div {
  height: 50px;
  display: flex;
  }

body > div > div {
  flex-basis: 50%;
  /* width: 50%; this works, as well */
  box-sizing: border-box;
}

#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

jsFiddle 演示


示例#3

在一个弹性容器中,你有box-sizing: border-boxand flex-grow,它会出现box-sizing不起作用......

body > div {
  height: 50px;
  display: flex;
  }

body > div > div {
  flex: 1;
  /* flex-basis: 50%; */
  /* width: 50%; this works, as well */
  box-sizing: border-box;
}

#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

jsFiddle 演示

但这并不正确...


示例 #4

flex-grow根据 flex 容器中的可用空间扩展flex 项的宽度。换句话说,它忽略了填充(和边框)。

但是,如果您简单地flex-grow与 一起指定flex-basisborder-box则将起作用:

flex: 1 1 50%; /* flex-grow, flex-shrink, flex-basis */

body > div {
  height: 50px;
  display: flex;
  }

body > div > div {
  flex: 1 1 50%; /* flex-grow, flex-shrink, flex-basis */
  /* flex-basis: 50%; */
  /* width: 50%; this works, as well */
  box-sizing: border-box;
}

#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

jsFiddle 演示

于 2015-10-15T12:20:06.817 回答
2

这不是错误,规范中清楚地描述了行为(清晰但不明显)。

这里是关于flex base size的。你可以阅读:

确定每个项目的弹性基本尺寸假设的主要尺寸

请注意假设的主要尺寸,这是这里的重要部分。

每个元素都有flex:1soflex-basis:0这意味着 flex 基本大小等于 0

A. 如果项目有明确的使用弹性基础,那就是弹性基础尺寸。

现在让我们继续到最后并阅读以下内容:

在确定 flex 基本尺寸时,忽略项目的最小和最大主尺寸

直到现在,它仍然可以。在查找 flex 基本大小时,我们会忽略所有内容。

让我们继续:

假设的主尺寸是根据其使用的最小和最大主尺寸(并将内容框尺寸设置为零)固定的项目的弹性基本尺寸。

假设的主尺寸考虑了元素尺寸,因此它将不同于弹性基本尺寸,在我们的例子中,我们有20px填充,所以假设的主尺寸等于20px

现在,如果您检查 flexbox 算法的其余部分,您会注意到假设的主尺寸是使用的那个,它为我们提供了填充变大的项目的逻辑结果。

对于这一步,弹性项目的大小是它的外部假设主要大小

将行上所有项目的外部假设主要尺寸相加

ETC

如果你删除它更微不足道flex-grow

body > div {
  height: 50px;
  display: flex;
}
body > div > div {
  flex-basis: 0;
  box-sizing: border-box;
}
#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
}
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

它们都具有0宽度,但具有填充的宽度将具有20px(其假设的主要尺寸而不是其弹性基本尺寸


避免这种情况的解决方案是确保所有项目都以相同的假设主尺寸结尾,因此我们需要确保flex-basis大于所有定义的填充、宽度、边框等。

@Michael_B 使用 flex-basis:50%,但您也可以使用flex-basis:40%orflex-basis:20px或任何大于20px和小于的值50%

body > div {
  height: 50px;
  display: flex;
}
body > div > div {
  flex-basis: 40%; /* between 20px and 50% will do the job*/
  flex-grow:1;
  flex-shrink:1;
  box-sizing: border-box;
}
#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
}
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

于 2021-08-27T22:32:12.680 回答
2

据我所知,这是正确的行为。

flex:1当然,它是以下的简写:

flex-grow:1;
flex-shrink:1;
flex-basis:0

这允许 div 在必要时增长,在这种情况下,它确实如此。如果弹性项目实际上不同,它不会自动将它们保持为所有相同的大小。

于 2015-10-15T10:03:24.057 回答
2

Tldr:这是一个错误。 参考1 ,参考2

Michael Benjamin 最后一个示例的替代解决方案:

适用flex-basis: 20px /*2 X padding of sibling*/于黄色div#d

body > div {
  height: 50px;
  display: flex;
}
body > div > div {
  flex: 1;
  box-sizing: border-box;
}
#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
  flex-basis: 20px;
}
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>


为什么上述解决方案有效?答案在于您的答案的实际问题。

实际问题:为什么弹性项目flex-basis:0没有得到宽度 k1/(k1+k2) 倍flex-container的宽度,当它有填充时?

答:因为,弹性项目的有效弹性基础是该弹性项目的padding-left+padding-right + border_left_width + border_right_width。Michael 所指的复杂数学是用户代理在确定' 长度时使用的整个算法的排序伪代码。flex-item在您的具体情况下,算法归结为:

if(flex_basis < (pading_left + padding_right + border_left_width + border_right_width)) {
  computed_flex_basis = pading_left + padding_right + border_left_width + border_right_width;
}

对于我们的例子,我们没有任何边界,所以让我们暂时忽略它。所以我们应该有flex_basis = pading_left + padding_right

证明:

body > div {
  height: 50px;
  display: flex;
}
body > div > div {
  flex: 1; /*flex-basis: 0%*/
  box-sizing: border-box; /*doesn't matter*/
  
}
.a {
  background-color: red;
  padding: 0 5px 0 10px;
}
.b {
  background-color: green;
  padding: 0 10px 0 10px;
  flex: 2;
}
.c {
  background-color: lightgreen;
  padding: 0 10px 0 15px;
  flex: 3;
}
.d {
  background-color: lightblue;
  padding: 0 15px 0 15px;
  flex: 3;
}

.a.mod {
  flex-basis: 15px;
}
.b.mod {
  flex-basis: 20px;
}
.c.mod {
  flex-basis: 25px
}
.d.mod {
  flex-basis: 30px;
}
<h2>flex-basis:0 for all flex-items</h2>
<div>  
  <div class="a"></div>
  <div class="b"></div>
  <div class="c"></div>
  <div class="d"></div>
</div>

<br><br>


<h2>flex-basis = padding_left + padding_right on all flex-items</h2>
<div>  
  <div class="a mod"></div>
  <div class="b mod"></div>
  <div class="c mod"></div>
  <div class="d mod"></div>
</div>

正如你所看到的,两者flex-basis: 0都是flex-basis: padding_left + padding_right等价的。不仅flex-basis<的任何值都padding_left + padding_right将被视为等同于flex-basis= padding_left + padding_right。至于为什么会发生这种行为,我认为这是w3.org here(Reference1 again) 所建议的某种不一致/错误。换句话说box-sizing: border-box,被忽略了。

于 2021-08-25T20:19:15.570 回答
-2

之所以发生这种情况,是因为你**padding****flex-basis** 字面意思更大。如果你只是改变它,它就会得到修复。

body > div {
  height: 50px;
  display: flex;
}
body > div > div {
  flex: 1;
  box-sizing: border-box;
}
#a {
  background-color: red;
}
#b {
  background-color: green;
}
#c {
  padding: 10px;
  background-color: blue;
}
#d {
  background-color: yellow;
  flex-basis: 20px;/*which is twice the padding of #c*/
}
<div>
  <div id="a"></div>
  <div id="b"></div>
</div>
<div>
  <div id="c"></div>
  <div id="d"></div>
</div>

于 2021-08-29T12:22:40.563 回答