w3c / csswg-drafts

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

[CSS2][CSSOM] Used value of margin properties #2328

Open mstensho opened 6 years ago

mstensho commented 6 years ago

I'm looking into how Window.getComputedStyle() behaves for margins.

https://drafts.csswg.org/cssom/#resolved-values

So the resolved value for margins is typically the used value. For percentage resolution and auto margin resolution, this seems to be what browsers do. However, nobody behaves according to spec in over-constrained situations:

https://www.w3.org/TR/CSS22/visudet.html#blockwidth

The spec says that the used value of either margin-left or margin-right should be changed to satisfy the constraint (margin + border + padding + width == containing block width).

Instead, all browsers just use the computed value of the margin property that should be overridden.

Example:

<div style="width: 400px;">
  <div id="elm" style="margin-left:0; margin-right:10px; width:100px;"></div>
</div>

The used value of #elm's margin-right should be 300px, but getComputedStyle(elm).marginRight returns 10px in both Chrome, Edge and Firefox.

Should this be considered browser bugs, or should the spec be fixed, or am I holding the specs wrong?

emilio commented 6 years ago

Seems like the example got lost, presumably because github strips html.

I think you need to wrap the examples in triple quotes like:

```html
<div></div>
\```

(without that backslash). Which will render as:

<div></div>
mstensho commented 6 years ago

Agh, I keep forgetting that. Thanks for pointing it out! Comment updated and fixed.

frivoal commented 6 years ago

am I holding the specs wrong?

No, I agree with the way you're reading this.

For percentage resolution and auto margin resolution, this seems to be what browsers do.

A quick bit of testing seems to show that all browsers do convert percentages to pixels, but that there isn't interop on auto. Chrome/Safari/Edge gives out the expected number of px, but Firefox resolves auto to 0px regardless of the actual size.

However, nobody behaves according to spec in over-constrained situations

That does match my testing.


mstensho commented 6 years ago

Right, Firefox doesn't resolve auto. I somehow failed to realize that.

One problem here is that, in order to honor the spec, user agents need to calculate values that the layout engine typically never uses. E.g. for a regular block in LTR, you never need to bother with the right margin at all. Just get the left margin correct. Still, the spec currently requires us to calculate a value for margin-right, so that we satisfy the constraint (width + fluff == containing block width).

Here's a more interesting test:

<div style="width: 400px;">
  <div style="float:left; width:100px; height:10px;"></div>
  <div id="elm" style="overflow:hidden; margin:auto; width:100px;"></div>
</div>

What's the used/resolved margin-left and margin-right here? We have a float that pushes #elm 100px to the right before we apply auto margins. So we have this: 100px of float, 100px of left margin, 100px of #elm border box and, finally 100px of margin right.

To satisfy the constraint, the sum of the used margins and the border box need to equal the width of the containing block, i.e. 400px. So it seems to me that the correct implementation would be to calculate a used margin-left of 200px and used margin-right of 100px. I've found no browser that does this. Chrome has margin-left:100px and margin-right:200px (weird!), while Edge pretends that the float isn't there (for the sake of getComputedStyle()) and has margin-left:150px and margin-right:150px. I guess this just goes to show that the current spec forces browsers to calculate values that are not needed by layout.

I think margins are really special here (due to 'auto' and over-constrainedness), and that it doesn't make sense to see how other properties are treated and compare with that.

emilio commented 5 years ago

This bit me while trying to implement an optimization in Firefox. Firefox returns what I think is the correct value in these test-cases:

```html

```

One WPT relies on us not doing this, and returning the pixel value as-is. My patch "fixed" the WPT, but given this issue I think I'm going to keep our behavior untouched for now, and reference this issue from the code. Also maybe fix the WPT, which is a rather naive one that isn't testing this in particular (http://w3c-test.org/css/css-box/parsing/margin-computed.html)

emilio commented 5 years ago

https://bugzilla.mozilla.org/show_bug.cgi?id=1404140 is the bug I was working on when fixing this, https://bugzilla.mozilla.org/show_bug.cgi?id=1570759 is the bug tracking potentially changing the behavior, since the Firefox behavior is inconsistent depending on whether we have percentage margins or not.

Loirooriol commented 6 months ago

This appeared during the discussion of #9174. CSS Align mandates a deviation from CSS2: https://drafts.csswg.org/css-align/#justify-block

In terms of CSS2.1 block-level formatting [CSS2], the rules for “over-constrained” computations in section 10.3.3 are ignored in favor of alignment as specified here and the used value of the margin properties are therefore not adjusted to correct for the over-constraint.