Skip to content

[css2][css-flow][cssom] How does avoiding floats affect margins? #9174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Loirooriol opened this issue Aug 9, 2023 · 4 comments
Open

[css2][css-flow][cssom] How does avoiding floats affect margins? #9174

Loirooriol opened this issue Aug 9, 2023 · 4 comments
Labels

Comments

@Loirooriol
Copy link
Contributor

https://drafts.csswg.org/css2/#floats

The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with overflow other than visible) must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space.

So the vertical adjustment to avoid floats is done with clearance, but what mechanism is used for the horizontal adjustment?

I see 2 reasonable options:

  1. The float is avoided by changing the used value of margins
  2. The float is avoided by adding some extra space additional to the margins. These space should then be taken into account in the equation in https://drafts.csswg.org/css2/#blockwidth

The thing is that getComputedStyle exposes the used margins: https://drafts.csswg.org/cssom/#resolved-value-special-case-property-like-height

If the property applies to the element or pseudo-element and the resolved value of the display property is not none or contents, then the resolved value is the used value. Otherwise the resolved value is the computed value.

However, note that for Gecko, Blink and WebKit, the used value is only for a computed auto. For a computed <length-percentage>, they just absolutize it into a length, even if there is over-constrainment and the used value is a different amount.
Servo still provides the used value even for a computed <length-percentage>.

Then, consider

<!DOCTYPE html>
<div style="border: solid; display: flow-root; width: 200px">
  <div style="float: left; width: 50px; height: 50px; background: cyan"></div>
  <div id="target" style="display: flow-root; height: 100px; background: magenta; margin-left: auto; margin-right: auto; width: 100px"></div>
</div>
<script>
document.body.append(getComputedStyle(target).marginLeft + ", " + getComputedStyle(target).marginRight);
</script>

Note that this is not clear in CSS2, but on all browsers the auto margins center the element within the space next to the float, not within the containing block:

This is what browsers say:

  • Gecko: 0px, 0px. auto is typically resolved to the used value, but just to 0px in the presence of floats.
  • Blink: 50px, 50px. Just resolves auto according to https://drafts.csswg.org/css2/#blockwidth, ignoring floats, without taking floats into account, even if the layout is completely different.
  • WebKit: 25px, 75px. It resolves margin-left: auto to the space between the rightmost left float to avoid and the border (like option 2 above). But then it resolves margin-left: auto according to https://drafts.csswg.org/css2/#blockwidth, ignoring floats.
  • Servo (option 1 above): 75px, 25px
  • Option 2 above: 25px, 25px

The behaviors of Gecko, Blink and WebKit seem nonsensical to me.

Also, if we want round-tripping, we must go with option 1 (or change how auto behaves in the presence of floats, but that seems more risky for compat).

@bfgeek
Copy link

bfgeek commented Aug 9, 2023

Blink recently changed this to fix a bug - and now behave like gecko (partially due to the round-tripping issue you describe).

Ian

@Loirooriol
Copy link
Contributor Author

So checking latest Blink I see that it always resolves auto to 0px (unlike Gecko, even if there are no floats).

This still doesn't round-trip: setting both margins to 0px in the example would place the element adjacent to the float instead of being separated by 25px.

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Jan 9, 2024

Blink changed again in https://chromium-review.googlesource.com/c/chromium/src/+/4930440 and aligned with Servo (option 1 above), which I think is the most reasonable behavior.

So Agenda+ to resolve on it. In particular:

  • Block-level elements that establish an independent FC avoid overlapping floats by changing the used value of their margin properties in the inline axis.
  • auto margins align within the free space after taking floats into account.
  • This is exposed in getComputedStyle. There is the remaining question of only doing it for auto (like Blink) or in all cases (like Servo).

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css2][css-flow][cssom] How does avoiding floats affect margins?, and agreed to the following:

  • RESOLVED: Auto margins align between the remaining space after accounting for floats (existing interoperable behavior)
  • RESOLVED: For elements with a principal box, getComputedStyle always returns used values
  • RESOLVED: We'd like resolved margins to round-trip
The full IRC log of that discussion <emilio> oriol: so CSS2 when translated in modern terminology, it says that a block level element which establishes an independent formatting context, shouldn't collapse its margins
<dbaron> s/collapse its margins/overlap the margin box of floats/
<emilio> ... it can do so by being moved next to the floats or below the floats
<emilio> ... if it's moved below then this is done by inserting clearance
<emilio> ... which is a well-defined concepts
<emilio> [room chuckles]
<emilio> dbaron: it's a defined concept
<emilio> oriol: problem is what to do in the inline axis
<emilio> ... by what mechanism are we placing this element next to the floats
<emilio> ... the proposal is to modify the used margin value to not overlap the floats
<emilio> ... we could introduce another concept instead
<emilio> ... I'd go with using margins
<emilio> ... this has one potential problem for the auto value
<emilio> ... because gCS exposes the used value of margins for auto
<emilio> ... (spec says always but they only do for auto).
<emilio> iank_: floats and margins don't work like you'd expect to
<emilio> ... margins start at the containing block edge
<emilio> not at the float edge
<emilio> ... so margins always are referring to the CB edge
<emilio> ... auto margins are different
<emilio> ... auto margins center in the area between the float and the edge of the CB
<emilio> oriol: right so question is what should getComputedStyle return
<emilio> ... gecko returns 0 and zero
<fantasai> [oriol reports the results of such testcases]
<fantasai> [they are various levels of broken]
<emilio> oriol: blink aligned with servo
<emilio> ... would like to resolve on them
<emilio> ... first proposed resolution would be that we avoid overlapping floats by changing the used margin
<emilio> iank_: don't wanna go down that road
<emilio> ... there are other mechanism that affect float positioning
<emilio> ... there's a lot of weird stuff in there, I think the current box is positioned
<emilio> oriol: but margin + border-box should be the width of the containing block
<emilio> ... should we drop that constraint?
<emilio> iank_: yes
<emilio> fantasai: that seems fine to drop in presence of floats
<emilio> q+
<emilio> astearns: this specific issue is about what value you report for gCS
<emilio> ... there are other things that affect placement of formatting contexts that affect that equation
<emilio> nicole: Can we get more consistent behavior across browsers without that constraint?
<emilio> iank_: yeah the biggest inconsistency is what to report for auto margins in gCS
<fantasai> emilio: is there inconsistency only in the presence of floats? e.g. if there's no floats, do we get reasonable results?
<emilio> iank_: in absence of floats you report the right values
<emilio> oriol: not sure if you clear what the reported behavior is
<fantasai> emilio: was curious about what the mechanisms are
<emilio> iank_: alignment of table cells
<emilio> ... might be a webkit-ism
<emilio> ... let me find the other ones
<astearns> ack fantasai
<Zakim> fantasai, you wanted to comment on alignment
<astearns> ack emilio
<emilio> fantasai: the border-box + margin-box filling the containing block we give up in the alignment spec via e.g. justify-self
<emilio> ... I think round-tripping via gCS would be great
<emilio> ... but I don't need we need to make the equation add up
<emilio> emilio: for round-tripping in this case you do need that equation to add up
<emilio> ... because the margin would start from the CB edge
<emilio> iank_: the other things that affect this is the webkit values of text-align
<emilio> ... which is equivalent to justify-self center
<emilio> dbaron: for the html alignment attrs?
<emilio> iank_: yes
<emilio> dbaron: gecko has similar ones
<emilio> oriol: I think we could resolve on auto margins centering in the remaining space which I don't think it's specified
<emilio> ... also that gCS should return a value that round trips
<emilio> ... so, align with blink and servo
<emilio> RESOLVED: Auto margins align between the remaining space after accounting for floats (existing interoperable behavior)
<dbaron> Unrelated side note: at least I still remember CSS2's float rules well enough to be able to write a testcase where browsers are not interoperable and get it to show non-interop on the first try:
<dbaron> https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cdiv%20style%3D%22width%3A%20200px%22%3E%0A%20%20%3Cdiv%20style%3D%22float%3A%20left%3B%20height%3A%20100px%3B%20width%3A%2010px%3B%20background%3A%20blue%22%3E%3C%2Fdiv%3E%0A%20%20%3Cdiv%20style%3D%22margin-left%3A%2020px%3B%20width%3A%2050px%3B%22%3E%0A%20%20%20%20%3Cdiv%20style%3D%22float%3A%20left%3B%20width%3A%2060px%3B%20height%3A%2020px%3B%20background%3A%2
<dbaron> 0fuchsia%22%3E%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Fdiv%3E (WebKit follows the letter of the spec; Gecko and Chromium follow the spec's resummarization that follows "Loosely: ".)
<emilio> astearns: resolving on round-tripping doesn't seem super-useful if you're an implementor reading the spec
<emilio> astearns: proposal is to spec that auto-margin values round trip in getComputedStyle()
<emilio> fantasai: we don't know how, one is what oriol said, the other is returning "auto"
<emilio> astearns: might not be web compatible
<emilio> fantasai: specifically for the float case you could round-trip to auto
<emilio> iank_: no no no no
<emilio> ... the reason why we aligned to Servo's behavior
<emilio> ... we moved towards FF but too aggressively (return 0 for auto margins)
<emilio> ... and got bug reports
<emilio> ... so we need to return a decent used value
<emilio> fantasai: your proposed resolution has 2 interpretation, if only one is workable then we should write that down
<emilio> dbaron: are there any cases where there's no non-auto-value that round-trips?
<emilio> dbaron: can't think of one off the top of my head
<emilio> dbaron: part of the lesson is that we shouldn't write specs in terms of constraints because they have solutions that don't add up to what you thought
<emilio> dbaron: can we resolve on a goal rather than an exact spec?
<emilio> dbaron: if we resolve that we want ^
<emilio> fantasai: there shouldn't be two different ways of fixing that
<florian> q+
<fantasai> emilio: Proposed resolution 1: return used values, proposed resolution 2: they must round-trip
<astearns> ack florian
<emilio> florian: I think we shouldn't edit in css2
<emilio> ... wherever it goes, not css2
<florian> s/ not css2/ not css2: it is not in a publishable state, and after a few years, we evidently do not know how to get it to a publishable state
<emilio> RESOLVED: For elements with a principal box, getComputedStyle always returns used values
<emilio> s/used values/used values for margins
<emilio> RESOLVED: We'd like resolved margins to round-trip
<emilio> [rant about css2]
<bramus> ScribeNick: bramus

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Monday afternoon
Development

No branches or pull requests

3 participants