w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.52k stars 673 forks source link

[css-sizing] Stretch-fitting inline size next to floats. #4028

Open mstensho opened 5 years ago

mstensho commented 5 years ago

https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing https://drafts.csswg.org/css-sizing-3/#auto-box-sizes

The spec currently doesn't provide a size keyword to achieve this effect, but there used to be one named "fill-available", then renamed to "fill", "stretch" and/or "stretch-fit".

The behavior is partially defined, though, in level 3. "The size a box would take if its outer size filled the available space in the given axis; in other words, the stretch fit into the available space, if that is definite."

Furthermore, the spec already refers to stretch-fit sizing as part of resolving fit-content, so my question is: How is stretch-fitting in the inline dimension affected by adjacent floats?

<style>
  .outerfloat { float:left; width:100px; height:100px; background:blue; }
  .stf { overflow:hidden; width:fit-content; background:yellow; }
  .spacer { float:left; width:300px; height:10px; }
</style>
<div style="width:500px;">
  <div class="outerfloat"></div>
  <div class="stf">
    <div class="spacer"></div>
    <div class="spacer"></div>
  </div>
</div>

Should the yellow box fit to the right of the yellow box, or go below, and use the entire width of its containing block?

fantasai commented 5 years ago

Interestingly enough, the answer varies: for boxes that establish an independent containing block, CSS2 says they fit in the remaining space after the float; for non-replaced blocks, the float is ignored. Probably fit-content and the stretch keyword should match this behavior, since it was their intention to provide a switch between the shrink-to-fit sizing and fill-available sizing behaviors in CSS2.

yisibl commented 4 months ago

There is a 17-star issue in Chrome that relies on the CSSWG to resolve the specification as soon as possible. https://issues.chromium.org/issues/41253915

yisibl commented 2 months ago

@dholbert Based on your description here[1], you're leaning towards stretch = 100% right?

[1]https://bugzilla.mozilla.org/show_bug.cgi?id=1920634

dholbert commented 2 months ago

That's my leaning, yeah, based simply on what the spec currently says about stretch-fit sizing filling the containing block:

Stretch-fit sizing tries to set the box’s used size to the length necessary to make its outer size as close to filling the containing block as possible while still respecting the constraints imposed by min-height/min-width/max-height/max-width.

https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing

I don't have especially strong feelings on this at the moment, though; if there are reasons to favor the other behavior, that's probably fine too.

bfgeek commented 2 months ago

So I have (very) strong feelings 😀 that it should go beside the float.

Basically the nice thing about the new stretch keyword is that it explains the other half of width:auto.

In Blink, we never resolve an auto length, instead we coerce it to either fit-content or stretch length depending on the context.

E.g. In grid layout auto behaves as stretch for non-replaced elements, and fit-content for replaced.

For block layout the rules are a little more complex but basically: replaced, tables, floats, and some form controls are fit-content everything else is stretch.

For new formatting contexts with "auto-as-stretch", all engines today consider the available space for this calculation as adjusted for floats.

Basically I'd like to keep the invariant that engines can coerce auto to fit-content, or stretch. (Note this also becomes important for calc-size() FWIW).

If we don't go down this path to fully "explain" auto we'd need to introduce a new variant, e.g. stretch-respecting-floats that I'd prefer not to do.

From the web-developer perspective if we go with the "next-to-float" definition:

If we go with the "clears-floats" definition:

The "next-to-float" definition is strictly more powerful for developers.

@dholbert - Does this make sense?

bfgeek commented 2 months ago

Re-reading Elika's initial response, I think my long-winded response is saying the same thing :P .

dholbert commented 2 months ago

@bfgeek yup, that makes sense to me - thanks for the explanation!

I like the idea of explaining auto lengths in terms of fit-content & stretch. If the Blink behavior gets us to that goal, that seems worthwhile.

bfgeek commented 2 months ago

I like the idea of explaining auto lengths in terms of fit-content & stretch. If the Blink behavior gets us to that goal, that seems worthwhile.

FWIW when we realized this, we did a refactor, and it simplified our auto behaviour significantly.

(maybe I'll write a blog post about this one day).

dholbert commented 2 months ago

Good to know. I filed https://bugzilla.mozilla.org/show_bug.cgi?id=1920816 to look into a similar refactoring on our side.

Loirooriol commented 2 months ago

However, auto isn't always 100% identical to fit-content or stretch, because in Blink both fit-content and -webkit-fill-available allow the fixed table layout mode, but width: auto doesn't (see #10937 for details).

yisibl commented 2 months ago

@bfgeek Currently in Chrome, overflow:hidden doesn't keep the input behind the float element (we have to use display: flow-root), is this as expected?

data:text/html;charset=UTF-8,<!doctype html>
    <div style="float:left; width:100px; height:100px; border:1px solid;">float: left</div>
    <input type="text" style="overflow:hidden !important; 
    width:-webkit-fill-available; width: -moz-available; border: 2px solid blue;">

image

bfgeek commented 2 months ago

@yisibl - So this is because by default <input> is display: inline-block if you change it to display: block it'll switch behaviour to the block-level new formatting-context behaviour.

display: inline-block receives the full containing block available inline-size (e.g. https://www.software.hixie.ch/utilities/js/live-dom-viewer/?saved=13124 ). Its somewhat complex as to why this is, but basically things that sit in a linebox have different rules to a block-level new FC.