2

The following third flex item has a flex-grow of non-zero value, which is 0.1. It might be reasonable and I also read a suggestion that it should take up 100% of any extra space, because the other flex items are 0, and cannot grow. This one is 0.1 and even 0.1 / 0.1 is 100% (as a ratio). However, in practice on Chrome and Firefox it only took 10% of the extra space. Why and how should it behave?

#container {
  display: flex;
  border: 1px dashed blue
}

#container div {
  border: 1px dashed orange
}

#container div:last-child {
  flex-grow: 0.1;
  background: #ccc
}
<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 1
    I believe that is because the remaining distributable space always has a minimum flex unit of `1`. If you have flex-grow values of less than 1, then the space will be a ratio of the flex-grow value. E.g. of you have 3 elements and they each have a `flex-grow: 0.1`, then they will each get 10% of the remaining distibutable space. However, if they have a `flex-grow: 1`, then they will get 1/(1+1+1) (aka one third) of the remaining space. – Terry Jan 03 '20 at 06:54

3 Answers3

6

However, in practice on Chrome and Firefox it only took 10% of the extra space.

This is correct behaviour.

Find the ratio of the item’s flex grow factor to the sum of the flex grow factors of all unfrozen items on the line. Set the item’s target main size to its flex base size plus a fraction of the remaining free space proportional to the ratio. flexbox-ref

From the above, the flex-grow value effectively indicates the percentage of the free space, and flex-grow: 1 represents 100% of the free space. Also, the size after flex-grow is added is derived by such an equation.

flex item's base size + (remaining free space * (flex item's flex factors / unfrozen flex item's flex factors))

If you specify 0.1 for flex-grow in the context of the question, remaining free space will be 0.1 times the initial free space:

If the sum of the unfrozen flex items’ flex factors is less than one, multiply the initial free space by this sum. If the magnitude of this value is less than the magnitude of the remaining free space, use this as the remaining free space. flexbox-ref

So, using the above formula, the size of the third flex item can be derived as follows:

flex item's base size + (initial free space * 0.1 * (0.1 / 0.1))

= flex item's base size + (initial free space * 0.1)

So the result of flex-grow: 0.1 is 10% of the initial remaining free space.

  • @nopole: Items that determine *remaining free space* include the following description. "If the sum of the unfrozen flex items’ flex factors is less than one, multiply the initial free space by this sum. If the magnitude of this value is less than the magnitude of the remaining free space, use this as the remaining free space. " [ref](https://drafts.csswg.org/css-flexbox-1/#remaining-free-space) –  Jan 03 '20 at 07:18
  • Therefore, even if the result of (*flex item's flex factors* / *unfrozen flex item's flex factors*) becomes 1, there is no problem –  Jan 03 '20 at 07:19
  • using this method, there actually is a way to specify `1, 1, 1` to divide all extra space among 3 flex items, and `0.1, 0.1, 0.1` to take only 30% of the extra space and divide them – nonopolarity Jan 03 '20 at 13:20
  • yes I think the key is "If the sum of the unfrozen flex items’ flex factors is less than one, multiply the initial free space by this sum" – nonopolarity Jan 03 '20 at 13:23
  • There is a finalized specs as well: https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#remaining-free-space – nonopolarity Jan 03 '20 at 13:44
  • and this note: Flex values between 0 and 1 have a somewhat special behavior: when the sum of the flex values on the line is less than 1, they will take up less than 100% of the free space. https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-flex-grow-factor – nonopolarity Jan 03 '20 at 13:45
1

From the specification you can read:

Flex values between 0 and 1 have a somewhat special behavior: when the sum of the flex values on the line is less than 1, they will take up less than 100% of the free space.

You can continue to read the detail of this section and you will understand why your 0.1 is actually 10% of the free space.

The important part:

This pattern is required for continuous behavior as flex-grow approaches zero (which means the item wants none of the free space). Without this, a flex-grow: 1 item would take all of the free space; but so would a flex-grow: 0.1 item, and a flex-grow: 0.01 item, etc., until finally the value is small enough to underflow to zero and the item suddenly takes up none of the free space

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • this did NOT work for me as you described it. I had a line like "grid-template-columns: 0.6fr 0.4fr;" and, allegedly, since 0.6+0.4 result in 1, it should take the entire space. in reality, it was smaller. I had to change it to "grid-template-columns: 6fr 4fr;" to acheive the desired behavior – Nir O. Sep 22 '21 at 15:22
  • @NirO. you are talking about grid and here it's about flexbox so your comment is irrelevant, you are probably in the wrong post – Temani Afif Sep 22 '21 at 15:28
  • same same. https://stackoverflow.com/questions/45870323/does-css-grid-have-a-flex-grow-function – Nir O. Sep 22 '21 at 15:43
  • @NirO. no it's not the same. We cannot explain a CSS grid behavior using the Flexbox algorithm, it doesn't make a lot of sense. That question is telling you that 1fr is *similar* to flex-grow but in any way they are the same. We are talking about two different world here – Temani Afif Sep 22 '21 at 16:01
0

The minimum is 1 as value for flex-grow. If you add 1 it will take upp the remaining of the space there. Default value is 0 for flex-grow, that is why your two first divs only take up the space that their value do. You will notice that it will behave different using flex-grow, if you take your first div and add flex-grow: 1; it will be the size as your last one. If you on the other hand take flex-grow: 2; it will be larger then the other two, but not twice as large as it could be interrupted it to be. In real projects I rarely use anything but flex-grow: 1;, if I want something to be twice as large or anything along those lines I use flex-basis or width. Hope this helps.

Check my snippet. If you want it to take up a scpecific percentage then use flex-basis or width properties.

#container {
  display: flex;
  border: 1px dashed blue
}

#container div {
  border: 1px dashed orange
}

.remaining-space {
  flex-grow: 1;
  background-color: deepskyblue;
}
<div id="container">
  <div>1</div>
  <div>2</div>
  <div class="remaining-space">3</div>
</div>
Dejan.S
  • 18,571
  • 22
  • 69
  • 112