-
Notifications
You must be signed in to change notification settings - Fork 764
Description
https://drafts.csswg.org/css2/#float-width
Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2 does not define the exact algorithm.
This is especially tricky in the presence of floats, clearance, and children that establish an independent formatting context.
However, we do seem to have good interoperability (at least in the block-level children case), even if there is no WPT coverage. So I would like to discuss resolving on this interoperable behavior.
Some interesting examples:
The max-content size may be bigger than necessary
<article style="display: inline-block; border: solid">
<div><!-- Just to prevent the parent from establishing an IFC, otherwise WebKit is different --></div>
<div style="float: left; width: 50px; height: 30px; background: cyan"></div>
<div style="float: right; width: 30px; height: 30px; background: yellow"></div>
<div style="float: left; clear: left; width: 70px; height: 20px; background: magenta"></div>
</article>It uses a width of 100px, even though 80px would suffice to avoid "breaking lines" between the cyan and the yellow floats.
The max-content size may not be big enough to avoid "breaking lines"
<article style="display: inline-block; border: solid; vertical-align: top">
<div style="float: left; width: 30px; height: 30px; background: cyan"></div>
<div style="float: left; width: 30px; height: 30px; background: yellow"></div>
<div style="overflow: hidden; width: 50px; height: 30px; background: magenta"></div>
</article>
<article style="display: inline-block; border: solid; vertical-align: top">
<div style="float: left; width: 30px; height: 30px; background: cyan"></div>
<div style="float: left; width: 30px; height: 30px; background: yellow"></div>
<div>
<div style="overflow: hidden; width: 50px; height: 30px; background: magenta"></div>
</div>
</article>
<article style="display: inline-block; border: solid; vertical-align: top">
<div style="float: left; width: 30px; height: 30px; background: cyan"></div>
<div style="float: left; width: 30px; height: 30px; background: yellow"></div>
<div></div>
<div style="overflow: hidden; width: 50px; height: 30px; background: magenta"></div>
</article>Note that the 2nd case just wraps the BFC root inside an intermediate container, and the 3rd case inserts and empty block before it. Both changes reduce the max-content size and then the BFC root no longer fits next to the floats.
If the block container contains block-level children (and is not a table wrapper box?):
In Servo I have tried to implement the behavior that I observed on other browsers, I haven't checked their source code but it seems to be:
For the max-content size,
- Let
max_sizebe 0px. This tracks the maximum size seen so far, not including trailing uncleared floats. - Let
left_floatsbe 0px. This tracks the size of the trailing uncleared left floats. - Let
right_floatsbe 0px. This tracks the size of the trailing uncleared right floats. - For each block-level child (including floats, ignoring abspos):
- Let
clearbe the the computed value of theclearCSS property of the child. - If the child continues the same BFC (instead of establishing an independent formatting context),
- Set
clear := both(this is to avoid adding its size to the floats)
- Set
- If
clearis different thannone,- Set
max_size := max(max_size, left_floats + right_floats)
- Set
- If
clearisleftorboth,- Set
left_floats := 0px
- Set
- If
clearisrightorboth,- Set
right_floats := 0px
- Set
- Let
sizebe the outer max-content size of the child, floored by 0px- Bug? Firefox doesn't floor when
clearis none and the element doesn't float - Bug? WebKit seems to floor
left_floats + right_floatsinstead of each float individually
- Bug? Firefox doesn't floor when
- If the child floats left,
- Set
left_floats := left_floats + size
- Set
- Else, if the child floats right,
- Set
right_floats := right_floats + size
- Set
- Else (the child doesn't float),
- Set
max_size := max(max_size, left_floats + right_floats + size) - Set
left_floats := 0px - Set
right_floats := 0px
- Set
- Let
- The max-content size is
max(max_size, left_floats + right_floats)
The min-content size is just the maximum among the outer min-content sizes of each float or in-flow block-level child.
Firefox flooring bug (?)
<article style="display: inline-block; border: solid; margin-right: 100px">
<div style="float: right; width: 50px; height: 30px; background: cyan"></div>
<div style="clear: left; overflow: hidden; width: 100px; height: 30px; background: magenta; margin-right: -500px"></div>
</article>
<article style="display: inline-block; border: solid">
<div style="float: right; width: 50px; height: 30px; background: cyan"></div>
<div style="overflow: hidden; width: 100px; height: 30px; background: magenta; margin-right: -500px"></div>
</article>There is no left float, so clear: left should have no effect. However, removing it causes Firefox to stop flooring the size of the BFC root by 0px before adding it to the floats, and then the container becomes 0px wide.
| Firefox | Blink/WebKit |
|---|---|
![]() |
![]() |
WebKit flooring bug (?)
<article style="display: inline-block; border: solid; margin-left: 25px">
<div style="float: left; width: 50px; height: 50px; background: cyan"></div>
<div style="float: left; width: 50px; height: 40px; background: yellow; margin-left: -75px"></div>
<div style="overflow: hidden; width: 50px; height: 50px; background: magenta;"></div>
</article>
<article style="display: inline-block; border: solid;">
<div style="float: left; width: 50px; height: 50px; background: cyan"></div>
<div style="float: right; width: 50px; height: 40px; background: yellow; margin-left: -75px"></div>
<div style="overflow: hidden; width: 50px; height: 50px; background: magenta;"></div>
</article>WebKit doesn't floor the floats individually, so left_floats + right_floats is 25px instead of 50px. This seems suboptimal since it forces the BFC root to move down.
| Firefox/Blink | WebKit |
|---|---|
![]() |
![]() |
If the block container establishes an inline formatting context:
There is less interoperability here, e.g.
<article style="display: inline-block; border: solid">
.<!-- Just to force the parent to establish an IFC on Blink -->
<div style="float: left; width: 50px; height: 30px; background: cyan"></div>
<div style="float: right; width: 30px; height: 30px; background: yellow"></div>
<div style="float: left; clear: left; width: 70px; height: 20px; background: magenta"></div>
</article>| Firefox | Blink/WebKit |
|---|---|
![]() |
![]() |
I haven't implemented this case yet so I don't have the details, but aligning with Firefox seems more consistent with the block-level children case. Blink and WebKit seem to ignore clear: left.







