html icon indicating copy to clipboard operation
html copied to clipboard

Spec text for naturalWidth and naturalHeight behavior isn't web-compatible, for cases where attributes are missing

Open dholbert opened this issue 7 months ago • 6 comments

What is the issue with the HTML Standard?

The HTML spec says the following about the naturalWidth and naturalHeight attributes on an img element:

The IDL attributes naturalWidth and naturalHeight must return the density-corrected natural width and height of the image, in CSS pixels, if the image has density-corrected natural width and height and is available, or else 0. [CSS]

This means these attributes should return 0 for SVG images that lack a natural width (and/or height) attribute on the root element. Firefox is the only browser that implements this behavior, but we've run into sites that depend on these attributes not returning 0, tracked as dependencies of https://bugzilla.mozilla.org/show_bug.cgi?id=1935269 .

I've filed bugs on Chromium and WebKit to align with the spec on this. If I'm correctly reading the Chromium bug, I think they've determined that this isn't possible, due to sites depending on their existing behavior (note that these sites are presumably all broken in Firefox currently as well).

I suggest we amend the spec to match the Chromium behavior (since it's web-compatible and seems more coherent than WebKit's behavior). Based on my testing, it seems like the Chromium behavior is the following:

  • If there is no naturalWidth, use 300 as the default naturalWidth.
  • If there's no naturalHeight and no natural aspect ratio, use 150 as the default naturalHeight.
  • ....or if there is a natural aspect ratio, then use that and the width to compute the naturalHeight.
  • Likewise if there's a natural aspect ratio and a known natural size in at least one axis, then use that to compute the other axis.

Note that we could also hypothetically amend the CSS "natural dimensions" spec text, https://drafts.csswg.org/css-images/#natural-dimensions , but that would have broader implications; so my preference is to handle this as a special case in the HTML spec, to give graceful behavior (rather than using 0) when these CSS-defined dimensions do not exist.

I've got a WPT that tests for the proposed behavior which Chrome passes, which I'm intending to add as a .tentative WPT test with a link to this spec issue.

dholbert avatar May 06 '25 18:05 dholbert

CC @fsoder @karlcow who've been involved on the Chromium and WebKit bugs, respectively. (@fsoder if I'm mischaracterizing your findings [about further improvements to Chromium on this being unshippable], please let me know. I'm currently using Chromium 137 dev as my reference implementation, and I'm assuming that further changes to align with existing spec text here aren't going to ship (per https://issues.chromium.org/issues/41357911#comment37 and subsequent comments about sites being broken ).

Note also that we have a WPT that expects the current spec behavior, which Firefox passes but Chromium/Safari fail (in slightly different ways, but the webcompat-relevant important thing is that they return a nonzero naturalWidth and naturalHeight when the width/height attributes are missing): https://wpt.fyi/results/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight.html

Note also that one of the broken sites here is icloud.com, which uses a SVG checkmark graphic that lacks intrinsic dimensions, and icloud sizes it based (in part) on its naturalWidth and naturalHeight attributes and hence doesn't paint it at all in spec-compliant browsers -- this is tracked as a Firefox webcompat issue in https://bugzilla.mozilla.org/show_bug.cgi?id=1923304

dholbert avatar May 06 '25 18:05 dholbert

Ah, I also just recalled/rediscovered that we've got a similar problem for the .width and .height attributes, noted in https://bugzilla.mozilla.org/show_bug.cgi?id=1935269#c17

Those are defined in terms of the "density-corrected natural width and height" of the image.

So any spec change here needs to be structured such that it yields a similar behavior-change for those attributes -- we shouldn't be patching the naturalWidth/naturalHeight APIs themselves, but rather the "density-corrected natural width and height" spec text (or perhaps the CSS spec text that this construct depends on -- though as previously noted, I'd favor leaving the CSS concepts unmodified and handle this as a sort of graceful-fallback in how those concepts are exposed in HTML).

dholbert avatar May 06 '25 18:05 dholbert

This makes perfect sense to me. Would you be willing to work on a spec PR?

domenic avatar May 07 '25 02:05 domenic

See also #533, #3510, and #3614.

annevk avatar May 07 '25 06:05 annevk

This makes perfect sense to me. Would you be willing to work on a spec PR?

Possibly! I suspect I can carve out some time for it next week.

In the meantime, a few updates: (1) I've added a .tentative WPT that expects my proposed behavior (which passes in Chrome) -- that's in a PR here, soon to be merged, at which point it'll be visible on wpt.fyi here: https://wpt.fyi/results/html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-unavailable.tentative.html

(2) I've posted a patch (which will land after some supporting work is reviewed) which implements my proposed behavior in Firefox and makes us pass the aforementioned WPT (matching Chrome). That patch is at https://phabricator.services.mozilla.com/D248150 , and the new behavior will tentatively be enabled by default in Firefox 140, but can be disabled by toggling about:config pref image.natural-size-fallback.enabled (added in that patch).

dholbert avatar May 08 '25 22:05 dholbert

Proposed spec-edit still coming eventually here; I'm currently finalizing some test updates and our implementation update, which will inform the proposed spec change.

As part of the spec changes here, there are two related situations that I found where we need to clarify things in the spec, related to .width and .height and their dependency on the density-corrected natural {width,height}. Both of these situations are about images that are not currently being rendered (e.g. display:none or detached from the DOM entirely). The spec says that img.{width,height} should simply fall back to returning the density-corrected natural width and height (if available) when not being rendered; but I found two cases where we have interop between Gecko/Chromium/WebKit on doing something different from that, where we may want to just adjust the spec to reflect that reality (or get buy-in from all parties on changing implementations if there's a compelling reason to do so):

(1) When the img has a width and/or height attribute: in that case, Gecko/Chrome/WebKit make img.width & img.height return that attribute-value instead of returning the naturalWidth/naturalHeight. Here's a testcase -- when you click the button, Chrome/Gecko/WebKit all show

naturalWidth, naturalHeight, width, height:
320, 240, 7, 5

which indicates that they're using the width and height attributes here.

(2) When the img using srcset with a density (e.g. "2x"), Gecko/Chrome/WebKit all return the non-density-corrected natural width and height from the .width and .height APIs when the image is not rendered (but they return the density-corrected natural width and height from the naturalWidth and naturalHeight APIs). Here's a testcase - when you click the button, Chrome/Gecko/WebKit all show

naturalWidth, naturalHeight, width, height:
160, 120, 320, 240

Notice that natural{Width,Height} disagree with {width,height} (by the 2x zoom factor), even though both sets of APIs are technically supposed to return the same thing (the "density-corrected natural width and height").

dholbert avatar May 30 '25 20:05 dholbert