A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/w3c/csswg-drafts/issues/8884 below:

[css-flexbox] Intrinsic main size algorithm for row flexboxes not web compatible · Issue #8884 · w3c/csswg-drafts · GitHub

Blink launched an implementation of the specified intrinsic sizing algorithm on Canary for a few days. It was quite clear that the algorithm for computing the intrinsic main size for single-line row flexboxes is not web compatible. min-content sizes are too big. Not yet sure about max-content sizes.

The existing web needs the container's min-content size to be 100px in the case below. But the specified algorithm gives it a width of 300px[1].

<style>
  .flex {
    display: flex;
    width: min-content; /* [2] */
    border: 2px solid;
  }
  span {
    float:left;
    height: 25px;
    width: 100px;
    background: orange;
  }
</style>

<!-- Container must be 100px wide to be web compatible. New algorithm makes it 300px -->
<div class="flex">
  <!-- flex-basis of this item is 300px. -->
  <!-- min-content contribution is 100px. -->
  <!-- desired flex fraction is negative -->
  <div>
    <span></span>
    <span></span>
    <span></span>
  </div>
  <!-- desired flex fraction is 0 -->
  <div id="some-other-item-where-flex-fraction-is-0"></div>
</div>

[1] chosen flex fraction == 0. So first item's final contribution is 300px + 0*0. Second item's final contribution is 0. Their sum is the min-content width of 300px.
[2] No one actually specifies width: min-content. But the container's min-content size percolates up to ancestor flexboxes (used in automatic minimum widths) or table cells (for fit-content sizing). The new larger min-content sizes cause compat problems for such ancestors.

We implemented a variant of the algorithm that is closer to what engines currently ship. In this variant, for containers where chosen flex fraction <= 0, items' final contribution to the container's min-content size is (1) its flex-basis if the item has a 0 flex factor in whichever direction it wants to go (shrink if flex-basis > min-content contribution, grow otherwise); otherwise: (2) its min-content contribution.

let ComputeIntrinsicSizes = (flex_container) => {
  // https://drafts.csswg.org/css-flexbox/#intrinsic-main-sizes
  let [container_min_size, container_max_size, chosen_flex_fraction] = ComputeIntrinsicMainSizesPerSection991();

  // chosen_flex_fraction <=0 means no item is growing from their flex basis
  // to meet their min contribution.
  if (flex_container.IsSingleLineRow() && chosen_flex_fraction <= 0) {
    container_min_size = 0;

    for (item in flex_container.items) {
      // https://drafts.csswg.org/css-flexbox/#intrinsic-item-contributions
      const min_contribution = item.ComputeMinContributionPerSection993();
      const base_size = item.flex_base_size;
      const cant_move = (item.shrink_factor == 0 && base_size > min_contribution) || 
                        (item.grow_factor == 0 && base_size < min_contribution);
      if (cant_move) {
        container_min_size += base_size;
      } else {
        container_min_size += min_contribution;
      }
    }
  }
  return { container_min_size, container_max_size };
}

In local testing, this variant has proven to be significantly more web compatible than what is currently specified, but possibly still insufficiently compatible. We haven't tested it in the wild.

We've also discussed, but haven't experimented much with, another variant even closer to what engines currently ship. In this variant, we don't examine flex fractions at all for min-content computations. Instead, each item's final contribution is (1) flex-basis if the flex-basis is not derived from the item's contents AND the item has a 0 flex factor in whichever direction it wants to go; otherwise: (2) its min-content contribution.

let ComputeIntrinsicSizes = (flex_container) => {
  // https://drafts.csswg.org/css-flexbox/#intrinsic-main-sizes
  let [container_min_size, container_max_size, chosen_flex_fraction] = ComputeIntrinsicMainSizesPerSection991();

  if (flex_container.IsSingleLineRow()) {
    container_min_size = 0;

    for (item in flex_container.items) {
      // https://drafts.csswg.org/css-flexbox/#intrinsic-item-contributions
      const min_contribution = item.ComputeMinContributionPerSection993();
      const base_size = item.flex_base_size;
      const cant_move = (item.shrink_factor == 0 && base_size > min_contribution) ||
                        (item.grow_factor == 0 && base_size < min_contribution);
      if (cant_move && item.basis != "content") {
        container_min_size += base_size;
      } else {
        container_min_size += min_contribution;
      }
    }
  }
  return { container_min_size, container_max_size };
}

Both of these variants break the promise, in some cases, that an item will end up at least as large as its min-content contribution after the flex algorithm runs. But that seems to be necessary given where the web is today. (Also, I omitted clamping by used min/max sizes in the descriptions above, but of course they need to be accounted for.)

@tabatkins @fantasai, you've thought about this algorithm a lot. Do you have ideas for variants that are more principled than our attempts, but that preserve current behavior in the reduced case presented above?

We haven't yet gotten as strong a signal on multiline row or multiline column flexboxes. Investigations ongoing.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.3