flex-grow不按预期调整flex项目的大小

时间:2016-01-06 23:27:25

标签: html css css3 flexbox

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

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

我在这里遗漏了什么吗?

' 0'的右侧应该与它上方的8,5和2对齐。它有点偏。

enter image description here



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

<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>
&#13;
&#13;
&#13;

https://jsfiddle.net/0r4hemdu/

5 个答案:

答案 0 :(得分:31)

简短分析

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

enter image description here

水平边距为10px时,第4行的可用空间比其他行多10px。这会抛弃列的对齐。

由于flex-grow仅适用于可用空间,并且受内容和边距的影响很大,因此它不是调整弹性项目大小的最安全方法。

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

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

.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; }
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>

扩展分析

您写道:

  

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

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

您写道:

  

在下面提供的小提琴中,你会看到一个数字键盘。除底行外,所有行都包含3个数字。那行应该是'0'是2个数字的宽度,因此flex-grow: 2和':'是1个数字的大小,因此flex-grow: 1。我在这里错过了什么吗?

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

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

当您应用flex-grow: 2时,您告诉Flex项目的可用空间是flex-grow: 1项目的两倍。

但是从上面的行中的第二个10px边距到第4行的布局是什么?

enter image description here

第4行关闭对齐的原因是第4行的边距比其他行少一个,这意味着第4行的空闲空间比其他行多10px。

你会注意到,如果你remove the margin rule得到了你想要的对齐方式。

.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;
}
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>

那么第四行到第二个10px边际会发生什么?

它被两个弹性物品吸收。

  

以下是flex-grow在第四行分配额外空间的方式:

     
      
  • 左侧的Flex项目(内容为“0”)有flex-grow: 2。 (代码中为.button#number0。)
  •   
  • 右侧的Flex项目(内容为“:”)有flex-grow: 1。 (代码中为.button#colon。)
  •   
  • 第二个项目间边距仅出现在具有三个弹性项目的行上,宽度为10px。 (代码说每个项目周围5px,但在   CSS horizontal margins never collapse。   此外,在flexbox中,no margins collapse。)
  •   
  • flex-grow值的总和为3。所以让我们将10px除以3.现在我们知道1的比例是3.33px。
  •   
  • 因此,flex项左侧获得额外空间6.66px,弹性项右侧获得3.33px。
  •   
  • 假设左侧的弹性项目改为flex-grow: 3。然后,左侧的弹性项目将获得7.5px,右侧的弹性项目将获得2.5px。
  •   

你问题的最后一部分说:

  

'0'的右侧应与其上方的8,5和2对齐。有点过了。

由于flex-grow仅适用于可用空间,并且受内容和边距的影响很大,因此它不是调整弹性项目大小的最安全方法。

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

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

.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; }
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>

jsFiddle demo

参考文献:

EXTRA:CSS GRID SOLUTION

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

.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;
}
<div class="numbers">
  <div class="button number" id="number1">1</div>
  <div class="button number" id="number2">2</div>
  <div class="button number" id="number3">3</div>
  <div class="button number" id="number4">4</div>
  <div class="button number" id="number5">5</div>
  <div class="button number" id="number6">6</div>
  <div class="button number" id="number7">7</div>
  <div class="button number" id="number8">8</div>
  <div class="button number" id="number9">9</div>
  <div class="button number" id="number0">0</div>
  <div class="button" id="colon">:</div>
</div>

答案 1 :(得分:10)

更新3:

我想出了另一种摆脱错位的方法。

此版本与2:nd更新一起使用原始html未触及,并使用伪元素创建按钮,包括按钮悬停/点击效果。

flex仅限版本

&#13;
&#13;
.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);
}
&#13;
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>
&#13;
&#13;
&#13;

flex版本,对于不支持新Flexbox模型的浏览器具有display: table备用。

&#13;
&#13;
.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);
}
&#13;
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>
&#13;
&#13;
&#13;

更新2:

除了Michael_B的答案,顺便提一下,这里有一个非常好的解释,这里有一个更新版本,实际上确实给出了所需的对齐方式,在这种情况下,不需要1-2 px。< / p>

以下是我的和Michael_B版本中的fiddle samplean image,其中边框已经增加了一点,以便更容易看到错位。

这一切都归结为当border / padding出现时,flexbox如何计算尺寸,您可以read more about in this post,需要设置box-sizing: border-box以及更多调整,在代码中注释。

以下是my fiddle和摘要

&#13;
&#13;
.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);
}
&#13;
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>
&#13;
&#13;
&#13;

<强> 更新

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

&#13;
&#13;
.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%;
}
&#13;
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1" data-nr="1"></div>
        <div class="button number" id="number2" data-nr="2"></div>
        <div class="button number" id="number3" data-nr="3"></div>
    </div>
    <div class="row">
        <div class="button number" id="number4" data-nr="4"></div>   
        <div class="button number" id="number5" data-nr="5"></div>
        <div class="button number" id="number6" data-nr="6"></div>
    </div>
    <div class="row">
        <div class="button number" id="number7" data-nr="7"></div>
        <div class="button number" id="number8" data-nr="8"></div>
        <div class="button number" id="number9" data-nr="9"></div>
    </div>
    <div class="row">
        <div class="button number" id="number0" data-nr="0"></div>
        <div class="button" id="colon" data-nr=":"></div>
    </div>
</div>
&#13;
&#13;
&#13;

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

&#13;
&#13;
.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;
  }  
}
&#13;
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1" data-nr="1"></div>
        <div class="button number" id="number2" data-nr="2"></div>
        <div class="button number" id="number3" data-nr="3"></div>
    </div>
    <div class="row">
        <div class="button number" id="number4" data-nr="4"></div>   
        <div class="button number" id="number5" data-nr="5"></div>
        <div class="button number" id="number6" data-nr="6"></div>
    </div>
    <div class="row">
        <div class="button number" id="number7" data-nr="7"></div>
        <div class="button number" id="number8" data-nr="8"></div>
        <div class="button number" id="number9" data-nr="9"></div>
    </div>
    <div class="row">
        <div class="button number" id="number0" data-nr="0"></div>
        <div class="button" id="colon" data-nr=":"></div>
    </div>
</div>
&#13;
&#13;
&#13;

答案 2 :(得分:7)

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

你遇到的问题更为普遍。你把太多的责任放在一个元素上。在这种情况下,它是.button类。灵活增长的Flex和Margin是太多的责任。试着打破这一点。它意味着更多的DOM元素,但它可以为您节省很多痛苦。

.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%;
}
<div class="numbers">
    <div class="row">
      <div class="box"><div class="button number" id="number1">1</div></div>
      <div class="box"><div class="button number" id="number2">2</div></div>
      <div class="box"><div class="button number" id="number3">3</div></div>
    </div>
    <div class="row">
      <div class="box"><div class="button number" id="number4">4</div></div>
      <div class="box"><div class="button number" id="number5">5</div></div>
      <div class="box"><div class="button number" id="number6">6</div></div>
    </div>
    <div class="row">
      <div class="box"><div class="button number" id="number7">7</div></div>
      <div class="box"><div class="button number" id="number8">8</div></div>
      <div class="box"><div class="button number" id="number9">9</div></div>
    </div>
    <div class="row">
      <div class="box box-2"><div class="button number" id="number0">0</div></div>
      <div class="box"><div class="button" id="colon">:</div></div>
        
        
    </div>
</div>

答案 3 :(得分:4)

在我看来,

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/

答案 4 :(得分:1)

使用速记来支持跨浏览器支持非常重要:

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