关于html:flex-grow未按预期调整flex项目的大小

flex-grow not sizing flex items as expected

似乎flex div中的内容会影响有关flex-grow属性的计算大小。 难道我做错了什么?

在下面提供的小提琴中,您将看到一个数字键盘。 除底行外,所有行均包含3个数字。 该行的'0'是2个数字的宽度,因此flex-grow: 2和':'(冒号)是1个数字的大小,因此是flex-grow: 1

我在这里想念什么吗?

" 0"的右侧应与其上方的8、5和2对齐。 有点不对劲

enter image description here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.numbers {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
    flex-grow: 1;
    justify-content: center;
    align-items: center;
    margin: 5px;
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(255, 255, 255, 0.2);
    cursor: pointer;
}

.button#number0 {
    flex-grow: 2;
}

.button#colon {
    flex-grow: 1;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

https://jsfiddle.net/0r4hemdu/


简短分析

问题在于,第1-3行有两个水平边距,而第4行只有一个水平边距。

enter image description here

如果水平边距各为10px,则第4行的可用空间比其他行多10px。这引发了列的对齐。

由于flex-grow仅适用于自由空间,并且受内容和边距的严重影响,因此,这不是确定伸缩项目大小的最安全方法。

请尝试使用flex-basis。将此添加到您的代码:

1
2
3
.button    { flex-basis: 33.33%; }
#number0   { flex-basis: calc(66.67% + 10px); }
*          { box-sizing: border-box; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.numbers {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
    flex-basis: 33.33%;
    justify-content: center;
    align-items: center;
    margin: 5px;
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(255, 255, 255, 0.2);
    cursor: pointer;
}

#number0   { flex-basis: calc(66.67% + 10px); }
*          { box-sizing: border-box; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

扩展分析

你写了:

It seems that the content inside a flex div affects its calculated size concerning the flex-grow property. Am I doing something wrong?

问题的根源不是弹性项目中的内容。

你写了:

In the fiddle provided below, you'll see a number pad. All the rows contain 3 numbers except the bottom row. That row should have the '0' be the width of 2 numbers, hence flex-grow: 2 and the ':' be the size of 1 number, hence flex-grow: 1. Am I missing something here?

是。您对flex-grow属性的解释不正确。 flex-grow不适用于定义弹性项目的大小。它的工作是在弹性容器中的各个项目之间分配可用空间。

通过将flex-grow: 1应用于一组弹性项目,可以告诉它们在它们之间均匀分配可用空间。这就是为什么在您的演示中,行1,行2和行3具有相同大小的弹性项目。

应用flex-grow: 2时,您要告诉flex项目消耗的空闲空间是flex-grow: 1项目的两倍。

但是,以上各行的第二个10px边距在第4行的布局中位于何处?

enter image description here

第4行未对齐的原因是,第4行的边距比其他行少一个,这意味着第4行的可用空间比其他行多10像素。

您会注意到,如果删除边距规则,则会得到所需的对齐方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.numbers {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
    flex-grow: 1;
    justify-content: center;
    align-items: center;
    /* margin: 5px; */
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(255, 255, 255, 0.2);
    cursor: pointer;
}

.button#number0 {
    flex-grow: 2;
}

.button#colon {
    flex-grow: 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

那么第四行到第二个10px的空白会发生什么呢?

它被两个弹性项目吸收。

Here's how flex-grow distributes the extra space on row four:

  • Flex item left (with content"0") has flex-grow: 2. (.button#number0 in your code.)
  • Flex item right (with content":") has flex-grow: 1. (.button#colon in your code.)
  • The second inter-item margin, which appears only on rows with three flex items, is 10px wide. (The code says 5px around each item, but in
    CSS horizontal margins never
    collapse.
    Moreover, in flexbox, no margins
    collapse.)
  • The sum total of the flex-grow values is three. So let's divide 10px by 3. Now we know that the proportion of 1 is 3.33px.
  • Hence, flex item left gets 6.66px of the extra space, and flex item right gets 3.33px.
  • Let's say that flex item left had flex-grow: 3 instead. Then flex item left would get 7.5px, and flex item right would get 2.5px.

您问题的最后一部分说:

The right side of the '0' should be aligned with the 8, 5, and 2 above it. It's a bit off.

由于flex-grow仅适用于自由空间,并且受内容和边距的严重影响,因此,这不是确定伸缩项目大小的最安全方法。

请尝试使用flex-basis。将此添加到您的代码:

1
2
3
.button    { flex-basis: 33.33%; }
#number0   { flex-basis: calc(66.67% + 10px); }
*          { box-sizing: border-box; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.numbers {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
    flex-basis: 33.33%;
    justify-content: center;
    align-items: center;
    margin: 5px;
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(255, 255, 255, 0.2);
    cursor: pointer;
}

#number0   { flex-basis: calc(66.67% + 10px); }
*          { box-sizing: border-box; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

jsFiddle演示

参考文献:

  • flex-grow定义?MDN
  • flex-basis定义?MDN
  • 7.2灵活性组件?W3C

额外:CSS GRID解决方案

随着CSS Grid的出现,可以大大简化整个布局的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.numbers {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(26%, 1fr));
  grid-gap: 10px;
}

#number0 {
  grid-column: span 2;
}


/* non-essential decorative styles */
.button {
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 5px;
  border: 1px solid gray;
}
1
2
3
4
5
6
7
8
9
10
11
  1
  2
  3
  4
  5
  6
  7
  8
  9
  0
  :


更新3:

我想出了另一种摆脱不对正的方法。

此版本与2:nd更新一起使用,原始HTML保持不变,并使用伪元素创建按钮,包括按钮悬停/单击效果。

flex仅限版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
.row {
  width: 60%;
  margin: auto;
  display: flex;
}
.button {
  flex: 0 0 33.3%;
  text-align: center;
  position: relative;
  padding: 10px 5px;
  box-sizing: border-box;
  pointer-events: none;
}
.button#number0 {
  flex: 0 0 66.6%;
}

.button:before,
.button:after {
  content:"";
  border-radius: 5px;
  border: 1px solid gray;  
  cursor: pointer;
  position: absolute;
  left: 5px;
  top: 5px;
  right: 5px;
  bottom: 5px;
  pointer-events: auto;
}
.button:before {
  background: rgba(255, 255, 255, 0.9);
  z-index: -1
}
.button:hover:before {
  background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
  border: 2px solid red;
}
.button:active:before {
  background: rgba(255, 0, 0, 0.5);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

对于不支持新的flexbox模型的浏览器,带有display: table后备版本的flex版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.row {
  display: table;              /* remove for flex only */
  width: 60%;
  margin: auto;
  display: flex;
}
.button {
  display:table-cell;          /* remove for flex only */
  width: 33.3%;                /* remove for flex only */
  flex: 0 0 33.3%;
  text-align: center;
  position: relative;
  padding: 10px 5px;
  box-sizing: border-box;
  pointer-events: none;
}
.button#number0 {
  width: 66.6%;                /* remove for flex only */
  flex: 0 0 66.6%;
}

.button:before,
.button:after {
  content:"";
  border-radius: 5px;
  border: 1px solid gray;  
  cursor: pointer;
  position: absolute;
  left: 5px;
  top: 5px;
  right: 5px;
  bottom: 5px;
  pointer-events: auto;
}
.button:before {
  background: rgba(255, 255, 255, 0.9);
  z-index: -1
}
.button:hover:before {
  background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
  border: 2px solid red;
}
.button:active:before {
  background: rgba(255, 0, 0, 0.5);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

更新2:

除了Michael_B的答案(很好地解释了)之外,这里还提供了一个更新版本,该版本实际上给出了所需的对齐方式,而在这种情况下,不偏离1-2 px。

这是我的版本和Michael_B版本的小提琴样本和图像,其中的边界略微增加了一点,以便于查看错位。

一切都取决于存在border / padding时flexbox如何计算大小,您可以在本文中了解更多信息,其中需要设置box-sizing: border-box并进行一些其他调整,该注释在码。

这是我的小提琴和摘录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.row {
    display: flex;
    width: calc(100% - 30px);   /* 30px = the sum of the buttons margin: 5px
                                          to avoid horizontal scroll            */

}

.button {
    display: flex;
    flex-basis: 33.33%;
    flex-shrink: 0;             /* we need flex-grow/shrink to be 1/0 to make
                                   it calculate the size properly               */

    box-sizing: border-box;     /* to take out the borders when calculate the
                                   flex shrink/grow factor                      */

    justify-content: center;
    align-items: center;
    margin: 5px;
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(0, 0, 0, 0.1);
    cursor: pointer;
}

#number0 {
    flex-basis: calc(66.66% + 10px);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        1
        2
        3
   
   
        4
        5
        6
   
   
        7
        8
        9
   
   
        0
        :

更新:

仅限flex版本,使用伪元素对现有html结构进行了很小的更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.row {
  display: flex;
}
.button {
  flex: 0 0 33.3%;
}
.button:after {
  content: attr(data-nr);
  display: block;
  border-radius: 5px;
  border: 1px solid gray;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  padding: 3px;
  margin: 5px;
  cursor: pointer;
}
.button#number0 {
  flex: 0 0 66.6%;
}
1
 

flex版本,使用伪元素对现有html结构进行了少许更改,并且对于不支持新的flexbox模型(如IE8 / 9)的浏览器具有display: table后备功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
.row {
  display: table;
  width: 100%;
}
.button {
  display: table-cell;
  width: 33.3%;
  padding: 5px;
}
.button:after {
  content: attr(data-nr);
  display: block;
  border-radius: 5px;
  border: 1px solid gray;
  background: rgba(255, 255, 255, 0.9);
  text-align: center;
  padding: 3px;
  cursor: pointer;
}
.button#number0 {
  width: 66.6%;
}


@supports (display: flex) {
  .row {
    display: flex;
  }
  .button {
    display: block;
    width: auto;
    flex: 0 0 33.3%;
    padding: 0;
  }
  .button#number0 {
    flex: 0 0 66.6%;
  }
  .button:after {
    margin: 5px;
  }  
}
1
 


我认为Michael_B所说的一切都是正确的。只有解决方案有点尴尬。我个人不喜欢calc。只是感觉不对。

您遇到的问题是一个更普遍的问题。您将太多的责任放在一个元素上。在这种情况下,它是.button类。 Flex和Margin以及flex-grow是太多的责任。尝试将其分开。它意味着更多的DOM元素,但为您省去了很多麻烦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
.numbers {
  display: flex;
  flex-direction: column;
  max-width: 200px;
  margin: 0 auto;
}

.row {
  display: flex;
  flex-direction: row;
  flex-grow: 1;
  justify-content: space-between;
}

.row > .box {
  display: flex;
  flex-basis: 33.3333%;
  justify-content: center;
  align-items: center;
}

.row > .box.box-2 {
  flex-basis: 66.6667%;
}

.button {
  border-radius: 5px;
  border: 1px solid gray;
  background: rgba(255, 255, 255, 0.2);
  cursor: pointer;
  width: auto;
  text-align: center;
  margin: 5px;
  width: 100%;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      1
      2
      3
   
   
      4
      5
      6
   
   
      7
      8
      9
   
   
      0
      :


我认为,flexbox对利润率的反应不佳。

我更喜欢的更好的方法/解决方法是,确保所有flex子代的边距为0,将flex容器设置为justify-content: space-between;,然后使子代的总宽度小于100%。剩下的就是您的保证金。

换句话说,如果您希望每行两个元素,请将每个元素设置为49%宽,并且它们之间将有2%的间距。三个元素,每个元素的宽度为32%,而您之间将有2%。在计算器示例中,0单元格应为66%宽,其余为32%。

编辑:请注意,由于原因(即content-box很糟糕),如果您的孩子有边框,您将需要使用box-sizing: border-box来使我的建议正常工作。

https://jsfiddle.net/r3L1mtbe/2/


使用简写来容纳跨浏览器支持很重要:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.row {
    display: flex;
    flex-direction: row; /* <-- this is the default so unnecessary to state */
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
   /* flex-grow: 1; replace with shorthand */
   flex:1 0 100%; /* probably making the"width: 100%;" unnecessary */
    justify-content: center;
}

.button#number0 {
    /* flex-grow: 2; replace with shorthand */
   flex:2 0 100%;
}

.button#colon {
    /* flex-grow: 1; replace with shorthand */
    flex:1 0 100%;
}