Home > OS >  Meaning of absolute values of flex-grow
Meaning of absolute values of flex-grow

Time:05-17

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?

CodePudding user response:

All ratios are 1:2 in the snippet below.

Spacing, when the combined sum of flex-grow is below 1.0, displays as it's designed to do, but not as you'd expect. And content without specifying flex-basis affects spacing distribution as well

Distribution of remaining space, as far as I can tell, uses or at least expects, integers. Meaning the flex-grow values represent proportions of the remaining space:

  1. Next we have to determine how much one flex-grow is

Now that we have the remaining space we need to determine into how many slices we want to cut it. The important thing here is that we don’t divide the remaining space by the number of elements, but by the number of total flex-grow values. So in our case that’s 3 (flex-grow: 2 flex-grow: 1)

178 / 3 = 59.33

remaining space / total flex-grow values = "one flex-grow"

So plugging your number into the equation,assuming the hypothetical space to be distributed is still 178 then you get:

178 / .3 = 593.33333

Which I'm assuming gets tossed out the window and you're left with defaults

const ratio1to2 = [.01, .04, .08, .1, .2, .3, .4, .5, .6, .7, .8, .9, 1, 2, 3, 4, 5, 50];

$(function() {
  ratio1to2.forEach(e => {
    let p2 = (e * 2);
    let html = `<div ><div style='flex-grow: ${e}'>${e}</div><div style='flex-grow: ${p2}'>${p2}</div></div>`;
    $("#placeholder1").append(html);
    $("#placeholder2").append(html);
  });
});
div#placeholder1,
div#placeholder2 {
  display: inline-block;
  border: 1px dashed green;
  padding: 4px;
}

.flexcontainer {
  margin-bottom: 4px;
  display: flex;
  width: 250px;
  gap: 4px;
}

.nobasis>.flexcontainer>div {
  border: 1px dashed red;
}

.basis20pct>.flexcontainer>div {
  flex-basis: 20%;
  border: 1px dashed blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="placeholder1" >
  No flex-basis, spacing not as expected
</div>
<div id="placeholder2" >
  flex-basis 20% spacing more consistent.
</div>

CodePudding user response:

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, the remaining space will be distributed in the same proportion. But it will only take up the part represented by the total; e.g. a .13 total means 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 30% of all the free space, not all of it.

  • Related