Closed (duplicate)
Project:
Drupal core
Version:
9.2.x-dev
Component:
responsive_image.module
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
25 Sep 2020 at 18:59 UTC
Updated:
14 Feb 2022 at 03:21 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
edysmpChecking this one.
Comment #3
edysmpChanged the title because the img tag is not always within a picture element, some times is just the img tag. This img tag does doesn't have set their dimensions, it uses the size and srcset attributes, so the the default loading attributes isn't added by the image theme preprocess, already committed.
Adding a patch that adds the loading=lazy attribute by default for images rendered by responsive_image module along with a small test.
The UI could be added it in this issue: https://www.drupal.org/project/drupal/issues/3173180
Comment #4
gaëlgThank you edysmp!
This patch adds the loading lazy attribute even if the height and width attributes are not set? It can lead to layout shifts.
I guess we should not add it if the dimension attributes are not present. And if core doesn't usually add these attributes, try to add them, where possible.
Comment #5
heddnNW for #4.
Comment #6
edysmpIn this case when are multiple files, what dimensions could be added to the img tag?
Wondering me if the browser will calculate the dimensions from the
<source>tags or thesizesattribute.For my researches, Responsive images could be rendered in two ways:
Using
pictureandimgtags.or just
imgtag.<img srcset="/sites/default/files/styles/max_325x325/public/2020-10/janik-rohland-fL8XSHbTQyg-unsplash.jpg?itok=5hAu3qJS 325w, /sites/default/files/styles/max_650x650/public/2020-10/janik-rohland-fL8XSHbTQyg-unsplash.jpg?itok=dINpFU2J 650w, /sites/default/files/styles/max_1300x1300/public/2020-10/janik-rohland-fL8XSHbTQyg-unsplash.jpg?itok=1KVTDx4j 1300w" sizes="(min-width: 1290px) 325px, (min-width: 851px) 25vw, (min-width: 560px) 50vw, 100vw" loading="lazy" src="/sites/default/files/styles/max_325x325/public/2020-10/janik-rohland-fL8XSHbTQyg-unsplash.jpg?itok=5hAu3qJS" alt="image 2" typeof="foaf:Image">Thoughts?
Comment #7
edysmpComment #8
gaëlgThat's the somewhat difficult question!
Brief explanation of the purpose of the various HTML things
The various source tags in a picture are used to give rules to browsers about what file to load. In your example, media queries are used as criteria for the two first source tags. The third source tag has a rule for the type of file supported by the browser, they must support jpeg to match this source tag.
If the browser matches the rule of the first source tag, it will load the file from this source tag. If not, it tries with the second source tag, and so on.
So these rules serve two purposes:
* "art direction", when you want a different image look and feel on different devices (like a portrait aspect ratio on mobiles and a landscape one on desktops, or like B&W images on phones, why not) : media queries
* browser file format support, like webp support (and a fallback usually, for browsers not supporting the first suggested format) : type attribute
Detailed documentation: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
The srcset attribute has only one usage (in source tags or in img tag): smartly take care of both various screen pixel densities (aka retina) and downloading performance. To display an image at a 200-wide size on a "normal" screen, you need a 200-wide file. But if the screen has a 300% pixel density for example, like HTC One, the finish will be better with a 600-wide file. So, we suggest different files to the browser. It will choose the better one for its needs, thanks to the "1x", "2x" or thanks to the "sizes" attribute and the width indication of each file with "325w", "650w".
In your example, the sizes attribute says: "Overall*, on 1290+px viewports, the display size will be 325px. On 851+px viewports, the display size will be a quarter of the viewport. On 560+px viewports, it will take half of the viewport and on smaller viewports it will take the whole viewport".
*Usually, the exact display size will be determined by CSS, but for good performance, the browser needs to have an idea of the display size soon enough, before it loads the CSS, so that he can choose the appropriate file: not too big for fast download, but not too small for a beautiful finish.
If it can help understand better, here's a real life HTML which displays images at a width of 800px, unless the viewport is too small, in which case the image is reduced to fit in the viewport:
Layout shift prevention
To prevent a layout shift, the real display dimensions of the not-yet-loaded image will be calculated by browsers, based on CSS, and as a fallback when CSS tells nothing or "auto", based on the sizes, width and height attributes.
So, width and height attributes are useful when CSS does not force them. Usually it gives width only, so height is auto-calculated from the image to keep a correct aspect ratio.
If CSS or the sizes attribute forces width (in pixels, percents,...), we only need to give the aspect ratio of the image, not the dimensions. I mean, we give height and width attributes, but browsers will only use those to determine aspect ratio and finally display height. So that it's the same to tell "w=100, h=200" or "w=200, h=400".
Detailed explanation here: https://www.smashingmagazine.com/2020/03/setting-height-width-images-imp...
When there is only an img tag, all files will actually have the same aspect ratio, so we can take the size of any file to set the width and height attributes. I'd take the one of the src attribute (fallback for browsers not supporting srcset).
When there is a picture tag with various sources using the type attribute, this is only a matter of file format, so the aspect ratio is the same for all files. Again, I would take the one of the src attribute of the inner img tag.
And when there are media queries on source tags, we have art direction, so that aspect ratio is not always the same. Unfortunately we cannot set width and height on source tags (https://github.com/whatwg/html/issues/4968). Aspect ratio is determined from the img tag (https://github.com/web-platform-tests/wpt/pull/24256), so it's the same for all. In that case, we can't prevent a little layout shift if the aspect ratio we give to the browser is not the one of the actual file loaded.
Some recommend to give the aspect ratio for mobiles, as they usually have lower bandwith so are more subject to late layout shifts (https://github.com/GoogleChrome/lighthouse/issues/10085#issuecomment-583...). Anyway, we have no easy way to know which source tag is the one for mobiles, so, again, we could use the img/src fallback (the site builder must choose it on his own).
Or we could (should) not give aspect ratio in that case, which means not enable native lazy loading to make sure we get no layout shift.
And now, what if CSS/sizes tells nothing about display width? This is unusual on real-life websites, but I guess it has to be somehow handled by Drupal core anyway. And obviously, we have no way in PHP to know about CSS rules.
I have two options in mind:
* let lazyloaded responsive images be enabled manually by site builders (in the settings file, or in UI as a follow-up), with a warning/disclaimer about the need to have CSS determine image width (or at least a well-crafted sizes attribute).
* give exact display dimensions in HTML, based on the "1x" file.
I kinda chose the first option in my Native Lazy Loading contrib module, but now that I write all this, I'm thinking the second one might be better.
So, to me, we would have this kind of algorithm :
Is there a source tag with a media query?
Yes: do nothing.
No: is there an srcset attribute on the img tag?
No: use the img src file size to set height and width attributes.
Yes: is there a sizes attribute on the img tag?
Yes: use the src file size to set height and width attributes.
No: use the size of the "1x" file to set height and width attributes.
Anyway, a second advice would be appreciated on this somewhat tough topic.
Comment #10
heddnI wonder if we need to add a UI element for this feature-set, just so we can let the site-builder configure a default height/width?
Comment #11
edysmpLetting the site-builder to select the default dimensions will be an option too.
Comment #12
heddnre #11: would that make things easier? I think it might.
Comment #13
edysmp@heddn you're right.
Comment #14
edysmpClosing it in favor of https://www.drupal.org/project/drupal/issues/3173180#comment-13893375.
Comment #15
pameeela commentedAdding #3192234: Apply width and height attributes to allow responsive image tag use loading="lazy" as related because that's the actual fix for this.
The other referenced issue (#3173180: Add UI for 'loading' html attribute to images) does not address responsive images anymore, which I only figured out after going through the pain of creating a patch for 9.3.x from the MR!