Meaning of absolute values of flex-grow

Issue

As I understand it, flex-grow on the child elements of a flex-ed element specifies how much of the relative proportion of space remaining to all the child elements should be allocated to a given element. So this:

<div style="display: flex;">
    <p style="flex-grow: 1; border: 1px solid purple;">First</p>
    <p style="flex-grow: 2; border: 1px solid gray;">Second</p>
</div>

means the second paragraph will take up twice as much of the remaining space as the first.

But if I change the absolute values of flex-grow while preserving the proportion between them:

<div style="display: flex;">
    <p style="flex-grow: .1; border: 1px solid purple;">First</p>
    <p style="flex-grow: .2; border: 1px solid gray;">Second</p>
</div>

the effect is not the same. What am I misunderstanding?

Solution

Per the flexbox draft spec:

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.

An item’s flex-grow value is effectively a request for some proportion of the free space, with 1 meaning “100% of the free space”; then if the items on the line are requesting more than 100% in total, the requests are rebalanced to keep the same ratio but use up exactly 100% of it. However, if the items request less than the full amount (such as three items that are each flex-grow: .25) then they’ll each get exactly what they request (25% of the free space to each, with the final 25% left unfilled). See § 9.7 Resolving Flexible Lengths for the exact details of how free space is distributed.

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. With this behavior, the item instead gradually takes less of the free space as flex-grow shrinks below 1, smoothly transitioning to taking none of the free space at zero.

Unless this “partial fill” behavior is specifically what’s desired, authors should stick to values ≥ 1; for example, using 1 and 2 is usually better than using .33 and .67, as they’re more likely to behave as intended if items are added, removed, or line-wrapped.

In other words:

  • if the total of all the flex-grows is >= 1, all the remaining space will be distributed proportionate to the different flex-grow values.
  • if the total is < 1, only part of the remaining space will be distributed in the same proportion — the part represented by the total. For example, if all the flex-grow values add up to .13, only 13% of the remaining space will be distributed. (This can be seen in the code snippet in fnostro’s answer).

The idea is that flex-grow: 0 (on a single item) takes up none of the empty space, and flex-grow: 1 (or greater) takes up all of it; and the values between 0 and 1 transition gradually between these two extremes. The same logic is applied when multiple items have a flex-grow set.

And so, in the second snippet of the question, the flexbox child items will only take up .3 or 30% of the free space, not all of it.

Answered By – Zev Spitz

Answer Checked By – Katrina (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.