Skip to content

[cssom-view] Layout dimension that divides+rounds+sums to value different to original dividend #1211

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
BevanR opened this issue Apr 13, 2017 · 4 comments

Comments

@BevanR
Copy link

BevanR commented Apr 13, 2017

Is there any specification for HTML layout dimensions that divide, round and sum to a value greater than the original dividend?

For example

  • A container has two columns.
  • Both columns are 50% the width of the parent.
  • The width of the container is 9 pixels.
  • How wide should each column be?

Major web browsers handle this differently;

Browser First Second element.offsetWidth Aliases †
Chrome 5 4 5 and 4 respectively No
Safari 5 4 5, even for the 4px column No
Firefox 4.5 4.5 rounded to 5 Yes
Edge 4.5 4.5 rounded to 5 Yes

† Allows element boundaries to be mid-pixel, causing that pixel to be aliased based on the two elements that it straddles.

row height screenshots
column width screenshtos

Test cases

The specification for offsetWidth only says that offsetWidth must be an integer. Is this specified elsewhere? Should it be?

Is this the correct place to discuss?

@zcorpan
Copy link
Member

zcorpan commented Apr 13, 2017

Thanks for looking into this and writing tests! This is indeed the right place.

Although the rendering can snap to device pixels, this can still be different from CSS pixels. In particular if there are two device pixels per CSS pixels (in one dimension), then both columns can be exactly 49.5px (without aliasing). Also with page zoom can affect this I believe.

Still, you demonstrated that there is lack of interop between Chrome and everyone else, so it would be good to come to an agreement which behavior is better and align on that.

If we say that all widths should add up to the same sum as the total width, how could that be implemented? For Firefox and Edge that allow the edge to cross a pixel, it seems they would need to do extra work to figure out which way to round offsetWidth for any given element, which seems both complex and expensive.

So I'm tempted to suggest that these should round in isolation (like Safari/Firefox/Edge), and we can add new non-integer APIs if any are missing.

@rune-opera thoughts?

@BevanR BevanR changed the title [cssom-view] Layout dimension that divides+rounds+sums to value greater than original dividend [cssom-view] Layout dimension that divides+rounds+sums to value different to original dividend Apr 13, 2017
@BevanR
Copy link
Author

BevanR commented Apr 13, 2017

The same issue exists with other more arbitrary divisions too. E.g. 10px÷3 or 70px split into 3 columns of 3, 4 and 5 units in a 12-column grid (using e.g. flexbox).

Of course it also applies to offsetHeight in the vertical dimension where row heights are divisions of the height of the container.

I created more test cases for the 10px÷3 scenario;

I believe what Chrome does to determine which element to add or remove the additional pixel to/from is;

  • round the left edge
  • round the right edge
  • make the width be the difference

(Safari and Chrome apply this to actual layout, shown by each column being different widths in the tests. Chrome also applies it to offsetWidth and offsetHeight. Safari does not, making the most incorrect browser for this unspecified behaviour; It reports the 4px row as 5px high in the row heights test case!)

Perhaps the solution is that offsetHeight and offsetWidth should be specified to be calculated in this way.

This doesn't require Firefox and Edge change their actual layout by requiring all elements have width and height dimensions that are integers. And offsetWidth and offsetHeight would still be inconsistent with the actual layout (in Firefox and Edge only), because they still must be integers. This is no more or less broken than their current behaviour. But at least offset dimensions would add to the sum of the container in all browsers. Also, Safari would then have to report what it is actually doing, and have the same behaviour as Chrome.

Website creators would then only need to deal with two different behaviours.

Workaround

I've documented a workaround at https://github.com/BevanR/5-and-5-is-9/

@zcorpan
Copy link
Member

zcorpan commented Apr 13, 2017

Rounding the edges is interesting.

An interesting case is if the width is 0.5px, it depends on where the edges are in the "CSS pixel grid" if offsetWidth is 0 or 1. However the result here does not match that of Chromium.
http://software.hixie.ch/utilities/js/live-dom-viewer/saved/5016

@zcorpan
Copy link
Member

zcorpan commented Apr 13, 2017

...at least not always, it appears it depends on page zoom level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants