Re: [css-flexbox] Resolving Flexible Lengths algorithm currently allows the "flex-shrink" value of a min-size-clamped flex item to impact other items' sizing

On 04/18/2014 10:44 AM, Daniel Holbert wrote:
> THE PROBLEM:
> ============
> Basically, the problem arises from these facts:
>  (a) The flex-shrink value of a given element can impact the "original
> desired free space" calculation for other elements, *even when the sum
> of the flex-shrink values is less than 1*, due to the way flex-shrink
> factors are scaled/renormalized. (Note that this isn't true of flex-grow
> values that sum to less than 1, which makes this not a problem for
> flex-grow.)
[...]
> So, the problem is that we calculate each item's "originally desired
> free space", and then we discover that one item needs to be frozen, and
> then for the remaining items, we *still* use their "original desired
> free space" values as the [negative] free space that they take, even
> though these values were calculated under the assumption that the frozen
> element would be taking some of the [negative] free space.

I'll expand on this a bit, with some concrete numbers & exact steps from
the algorithm.

I'll be comparing the 1st & 2nd examples from my testcase here:
 http://people.mozilla.org/~dholbert/tests/flexbox/flex-shrink-1.html

So in both examples, we have a flex container with main-size 250px, and
two flex items, whose flex base sizes are 200px and 100px.

The first flex item also has "min-width:200px" (keeping it from actually
shrinking), and has a flex-shrink of either 0.6 (first example) or 0.1
(second example). The second flex item has a flex-shrink of 0.4.

Steps below are from section 9.7:
 http://dev.w3.org/csswg/css-flexbox/#resolve-flexible-lengths

 Step 1: The used flex factor is "flex-shrink".
 Step 2: (nothing happens)
 Step 3: Free space = 250px-(200px+100px) = -50px
 Step 4, for the FIRST EXAMPLE:
   a) sum the flex-shrink factors: 0.6 + 0.4 = 1.0
   b) Multiply each flex-shrink factor by its flex base size:
      first item: 0.6 * 200px = 120
      second item: 0.4 : 100px = 40
        (which sum to 160)
   c) Renormalize flex shrink factors to sum to 1.0 (from (a)):
      first item: 120 * 1.0/160 = 0.75
      second item: 40 * 1.0/160 = 0.25
   d) Multiply those ^ by free space to get orig desired free space:
      first item: 0.75 * -50px = -37.5px
      second item: 0.25 * -50px = -12.5px

 Step 4, for the SECOND EXAMPLE:
   a) sum the flex-shrink factors: 0.1 + 0.4 = 0.5
   b) Multiply each flex-shrink factor by its flex base size:
      first item: 0.1 * 200 = 20
      second item: 0.4 : 100 = 40
        (which sum to 60)
   c) Renormalize flex shrink factors to sum to 0.5 (from (a)):
      first item: 20 * 0.5/60 = 0.1667
      second item: 40 * 0.5/60 = 0.3333
   d) Multiply those ^ by free space to get orig desired free space:
      first item: 0.1667 * -50px = -8.33px
      second item: 0.3333 * -50px = -16.67px

(So as you can see, we end up arriving at **different** "originally
desired free space" values for the second item (-12.5px vs -16.67px),
when we vary the **first item's** flex-shrink value.)

Then we end up entering the loop (Step 5):
 - On the first loop iteration, we freeze the first flex item.
 - On the second loop iteration, we set the second flex item's "desired
free space" to its originally desired free space value calculated above
(-12.5px in the first example, -16.67px in the second example), and then
we add this "desired free space" to the second item's main size.

So, we end up with the second item having a final width of 87.5px in the
first example, and 83.33px in the second example.

(Note that we skip the "normalize" step in the loop, since the free
space is less than (more negative than) the sum of our desired free
space values.)

~Daniel

Received on Friday, 18 April 2014 19:09:20 UTC