Patches to use for Drupal 9:

"patches": {
  "drupal/core": {
    "Order image mappings by breakpoint ID and numeric multiplier": "https://www.drupal.org/files/issues/2022-05-19/3267870-9.5.x-47.patch",
    "Apply width and height attributes to responsive image tag": "https://www.drupal.org/files/issues/2022-09-30/3192234-228-9.5.x.patch"
  },
}

And for Drupal 10.0:

"patches": {
  "drupal/core": {
    "Order image mappings by breakpoint ID and numeric multiplier": "https://www.drupal.org/files/issues/2022-05-19/3267870-9.5.x-47.patch",
    "3192234: Apply width and height attributes to responsive image tag": "https://www.drupal.org/files/issues/2023-04-07/3192234-293-10.0.x.patch",
  },
}

Problem/Motivation

While playing with lazy loading attribute that is coming from Drupal core and our own implementation in #3060605: Support lazy loading of images @sasanikolic noticed that responsive image tag is missing width and height attribute. Why is Drupal core is not setting these attributes for lazy image loading which basically disable lazy loading for all responsive images? The short answer is that responsive images are more complicated. And it still needs to be implemented.

I've read quite a bit of info related to lazy loading and images and responsive images in the next resources:

In short, at least as I understand, the problem with lazy loading and responsive images was that in one moment browsers were not properly supporting width/height attributes when images were lazy-loaded. So the browsers were not able to calculate the aspect ratio of images and show image area while image was still loading - and this resulted in recalculating page layout on image load. However, this should be fixed in most or all browsers now and this combination should work.

Proposed resolution

  • Add width and height attributes to the responsive image tag.
  • Add an option to toggle the loading="lazy/eager" option in the picture field formatter. For this, see the great work being done in #3173180: Add UI for 'loading' html attribute to images. We should model a similar result for picture.

A UI toggle is needed in this issue. We've learned a few things since loading="lazy" has started to be heavily used. Mainly, always enabling it negatively affects the page's LCP score. See https://web.dev/lcp-lazy-loading/ for an exhaustive description of the problem.

Remaining tasks

We want to avoid browser reflow if loading=lazy is configured.

From #13:
The HTML spec has very recently been updated to allow for width and height attributes to be set on source elements:

https://github.com/whatwg/html/issues/4968
https://twitter.com/zcorpan/status/1365046132401913861
https://twitter.com/jensimmons/status/1365066057774493697

Current browsers implementation:

As of Oct 5th, 2021, it looks like FF is the only major browser not currently supporting this. Safari and Chrome already do.

The image dimensions are always provided. The srcset attribute only supports a single set of dimensions. These
dimensions reflect the real size but all images should follow the same
image size ratio. If using sizes and art direction, that might not be true.
For image styles, that is less of a concern because specifying image
density should already require that all images are the same image size
ratio. One could argue that providing wrong dimensions for sizes attribute
is bad for art direction. But having some image size to calculate ratio
is better than providing nothing. Ergo, we provide dimensions in all cases
even though they might be wrong in some edge scenarios.

These image dimensions are used by the browser to calculate the size and render a placeholder. This avoids content shift on page load. If someone decided to use lazy loading and art direction, they should not use sizes attribute. But rather image styles and specify the image dimensions. Because if they don't then they could conceivably experience some content shift issues.

User interface changes

Minor wording change due to #137:

See #237 for more details about this mild regression:

With patch:

Without patch:

API changes

None.

Data model changes

None.

Release notes snippet

Responsive images now support lazy loading. Modules or install profiles that include default responsive image configuration should update their default config to include the new setting.

CommentFileSizeAuthor
#308 3192234-10.0.x-fallbacksize.patch38.76 KBklemendev
#302 code.png45.04 KBklemendev
#302 settings.png83.17 KBklemendev
#300 picture.png30.31 KBanybody
#293 3192234-293-10.0.x.patch49.39 KBberdir
#251 Screen Shot 2022-10-27 at 10.55.41.png1.33 MBgraber
#241 3192234-241-9.5.x.patch26.09 KBduaelfr
#238 with-patch.png103.02 KBheddn
#237 with-patch.png65.32 KBheddn
#237 no-patch.png93.93 KBheddn
#228 3192234-228-9.5.x.patch46.12 KBberdir
#227 interdiff_226-227.txt774 bytesheddn
#227 3192234-227.patch48.92 KBheddn
#226 interdiff_217-226.txt3.04 KBheddn
#226 3192234-226.patch48.92 KBheddn
#220 reroll_diff_191_220.txt4.85 KBtimohuisman
#220 3192234-220-9.4.x.patch44.36 KBtimohuisman
#217 interdiff_215-216.txt405 bytespooja saraah
#217 3192234-216.patch46.33 KBpooja saraah
#215 interdiff_207-215.txt3.75 KBheddn
#215 3192234-215.patch46.33 KBheddn
#207 3192234-206.patch44.68 KBsmustgrave
#207 interdiff-204-206.txt842 bytessmustgrave
#204 3192234-204.patch44.68 KBsmustgrave
#204 interdiff-191-204.txt4.68 KBsmustgrave
#191 3192234-191.patch44.37 KBheddn
#190 interdiff_183-190.txt4.2 KBheddn
#190 3192234-190.patch70.7 KBheddn
#183 3192234-183.patch44.17 KBheddn
#178 3192234-178.patch46.96 KBheddn
#178 interdiff_176-178.txt3.43 KBheddn
#176 interdiff-3192234-175-176.txt478 bytesyogeshmpawar
#176 3192234-176.patch46.96 KByogeshmpawar
#175 3192234-175.patch46.96 KBheddn
#175 interdiff_173-175.txt8.28 KBheddn
#173 interdiff_171-173.txt1.55 KBheddn
#173 3192234-173.patch42.49 KBheddn
#171 interdiff_158-171.txt6.54 KBheddn
#171 3192234-171.patch41.78 KBheddn
#163 eager-render.png91.71 KBheddn
#163 views-lazy.png54.49 KBheddn
#158 3192234-158.patch38.4 KBheddn
#158 interdiff_150-158.txt5.33 KBheddn
#155 Xnip2022-02-10_06-45-46.png586.68 KBzcht
#150 interdiff_149-150.txt747 bytesranjith_kumar_k_u
#150 3192234-150.patch36.44 KBranjith_kumar_k_u
#149 3192234-149.patch36.49 KBheddn
#149 interdiff_129-149.txt905 bytesheddn
#149 2022-02-03_10-16.png33.26 KBheddn
#142 2022-01-13_08-30.png15.68 KBheddn
#129 interdiff-3192234-128-129.txt519 bytespivica
#129 3192234-129.patch35.61 KBpivica
#128 interdiff-3192234-124-128.txt2.6 KBpivica
#128 3192234-128.patch35.84 KBpivica
#128 Selection_004.png981.73 KBpivica
#128 Selection_003.png318.01 KBpivica
#128 Selection_002.png14.17 KBpivica
#124 3192234-124.patch35.73 KBpivica
#122 interdiff-3192234-116-122.txt1.84 KBpivica
#122 3192234-122.patch35.73 KBpivica
#119 3192234-9.2.x-reroll-119.patch4.06 KBluke.leber
#116 3192234-116.patch34.8 KBheddn
#116 interdiff_109-116.txt3.3 KBheddn
#110 Screen Shot 2021-10-18 at 5.31.51 PM.png434.82 KByogeshmpawar
#109 interdiff-3192234-108-109.txt3.55 KByogeshmpawar
#109 3192234-109.patch33.74 KByogeshmpawar
#108 3192234-108.patch33.74 KBheddn
#108 interdiff_107-108.txt8.38 KBheddn
#107 interdiff_106-107.txt1.63 KBheddn
#107 3192234-107.patch27.4 KBheddn
#106 3192234-103.patch26.72 KBheddn
#105 3192234-105.patch17.31 KBqusai taha
#104 3192234-103.patch26.72 KBheddn
#104 interdiff_102-103.txt3.06 KBheddn
#102 3192234-102.patch26.79 KBheddn
#102 interdiff_98-102.txt4.06 KBheddn
#98 interdiff_85-98.txt21.3 KBheddn
#98 3192234-98.patch24.91 KBheddn
#87 After Patch 3192234.png967.74 KBchetanbharambe
#87 Before Patch 3192234.png891.05 KBchetanbharambe
#85 interdiff_84-85.txt718 bytesdevkinetic
#85 3192234-85.patch4.22 KBdevkinetic
#84 3192234-84.patch3.68 KByogeshmpawar
#81 3192234-81.patch3.56 KBqusai taha
#80 3192234-80.patch3.62 KBqusai taha
#79 3192234-79.patch3.56 KBqusai taha
#76 interdiff_74-76.txt1.5 KBvsujeetkumar
#76 3192234-76.patch4.18 KBvsujeetkumar
#74 3192234-74.patch2.49 KBahmad abbad
#73 3192234-73.patch4.22 KBPhil Wolstenholme
#72 3192234-72.patch8.55 KBPhil Wolstenholme
#70 3192234-70.patch4.22 KBPhil Wolstenholme
#69 Screenshot 2021-09-01 at 15.03.08.png65.96 KBPhil Wolstenholme
#59 3192234-60.patch4.11 KBberdir
#56 interdiff_3192234_47-56.txt2.53 KBmaximpodorov
#56 3192234-56.patch3.99 KBmaximpodorov
#47 3192234-47.patch3.95 KBglynster
#35 interdiff_3192234_30-35.txt1.46 KBankithashetty
#35 3192234-35.patch4 KBankithashetty
#32 Screenshot 2021-05-20 at 15.28.38.png146.67 KBgauravvvv
#32 Screenshot 2021-05-20 at 15.29.22.png214.27 KBgauravvvv
#30 3192234-30.patch3.93 KBDaniel Ward
#30 3192234-30-TEST-ONLY-FAIL.patch1.57 KBDaniel Ward
#30 interdiff_25-30.txt1.01 KBDaniel Ward
#29 image.png355.61 KBmahtabalam
#25 3192234-25.patch3.21 KBDaniel Ward
#25 interdiff_10-25.txt1.13 KBDaniel Ward
#24 4-picture-source-after.png123.89 KBflyke
#24 3-lighthouse-diagnostics-before.png24.83 KBflyke
#24 2-picture-source-before.png120.08 KBflyke
#24 1-lighthouse-diagnostics-before.png27.59 KBflyke
#10 interdiff_8-10.txt669 bytesnikitagupta
#10 3192234-10.patch2.14 KBnikitagupta
#8 interdiff-3192234-2-8.txt1.62 KBpivica
#8 apply-width-height-attributes-responsive-image-3192234-8.patch1.3 KBpivica
#6 Responsive images aspect ratio.png111 KBsasanikolic
#2 apply-width-height-attributes-responsive-image-3192234-2.patch805 bytespivica
#2 Selection_198.jpg274.72 KBpivica
#2 Selection_196.png75.41 KBpivica
#2 Selection_197.png90.58 KBpivica

Issue fork drupal-3192234

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

pivica created an issue. See original summary.

pivica’s picture

Status: Active » Needs review
StatusFileSize
new90.58 KB
new75.41 KB
new274.72 KB
new805 bytes

Here is a first patch. I've tested in Chrome with and without patch and you can see results:

Without the patch, the responsive image still not loaded:

With a patch, the responsive image still not loaded:

Responsive image fully loaded:

We can clearly see that, at least in Chrome, setting width and height attributes are helping because the browser can correctly calculate the aspect ratio of an image which is still not lazy loaded and reserve space in layout for it, so layout recalculation will be avoided when the image is loaded.

The only thing I am not sure is about which width/height attribute should we use. For example with this patch HTML looks like this:

<img srcset="/sites/default/files/styles/primer_content_xs/public/2017-05/hero-image.jpg?itok=IYRyuQr6 461w, /sites/default/files/styles/primer_content_sm/public/2017-05/hero-image.jpg?itok=2ciM9lmJ 800w, /sites/default/files/styles/primer_content_md/public/2017-05/hero-image.jpg?itok=xbh2RkS5 1200w, /sites/default/files/styles/primer_content_lg/public/2017-05/hero-image.jpg?itok=fpSgIiKy 1640w, /sites/default/files/styles/primer_content_xl/public/2017-05/hero-image.jpg?itok=LUnG3dSV 2186w" sizes="(min-width:1366px) 1332px, (min-width:992px) 930px, (min-width:768px) 690px, (min-width:576px) 510px, calc(100vw-30px)" src="/sites/default/files/styles/primer_content_md/public/2017-05/hero-image.jpg?itok=xbh2RkS5" width="7152" height="2496" alt="Thumbnail" title="Front hero image" loading="lazy" class="img-fluid">

Notice that `width="7152" height="2496"` which are actually dimension of source image. Maybe instead of this, we should use the dimension of 'Fallback image style' from responsive image settings? However, this would complicate code more and we really do not need it because we only need values from which browser can calculate the correct aspect ratio.

Status: Needs review » Needs work
gaëlg’s picture

Not much time right now, but in case it can help, I worked on this kind of problem in https://www.drupal.org/project/native_lazy_loading and #3173231: Enable lazy-load by default for responsive images.

pivica’s picture

@GaëlG thanks for your feedback.

I've checked #3173231: Enable lazy-load by default for responsive images and related #3173180: Add UI for 'loading' html attribute to images. IMHO these things are not quite the same. Related issues are still working around responsive images and lazy loading. This issue is just stating that the width and height attribute for responsive images are missing and that create above described problems.

I've checked #3173180 MR (https://git.drupalcode.org/project/drupal/-/merge_requests/43/diffs) and I don't see that that MR is fixing described issues. Maybe I am missing something, will ask in #3173180 about this.

sasanikolic’s picture

Status: Needs work » Needs review
StatusFileSize
new111 KB

I tested this and would agree that the width/height should be set by default also for responsive images. Also, the width and height should be set from the default/fallback responsive image, and not from the uploaded image itself, in order to have the correct aspect ratio.

See the screenshot attached. From the uploaded image: 1600/1000 = 1.6 aspect ratio, while the responsive image has 1339/837 = 1.533 aspect ratio.

pivica’s picture

Status: Needs review » Needs work

Agree with @sasanikolic for getting w/h from default/fallback responsive image.

pivica’s picture

Status: Needs work » Needs review
StatusFileSize
new1.3 KB
new1.62 KB

Here is a first version that is getting width and height attributes values from responsive image fallback style.

Status: Needs review » Needs work
nikitagupta’s picture

Status: Needs work » Needs review
StatusFileSize
new2.14 KB
new669 bytes

fixed the test case.

heddn’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

I think this could use some explicit tests.

joran lafleuriel’s picture

Nice initiative. Thanks.
I tried #10. But Responsive images were shown twice their size because I am using "Retina Images" module with x2 density parameter enabled.

Phil Wolstenholme’s picture

Hi everyone, I've got some relevant news:

The HTML spec has very recently been updated to allow for width and height attributes to be set on source elements:

This means the browser will 'copy' the width and the height values to the img element for us, just like it does for the src value. Perhaps this means this work should put attributes on the source elements, rather than using the fallback width and height on the img element? Or perhaps both approaches could be used to maximise browser support?

Chromium intends to ship this feature: https://groups.google.com/a/chromium.org/g/blink-dev/c/GEjjJE0LCnM/m/0p8...

pivica’s picture

> I tried #10. But Responsive images were shown twice their size because I am using "Retina Images" module with x2 density parameter enabled.

@ratjaune this is correct behaviour, it is expected that you have some parent wrapper that is controlling your image size based on your grid, layout, etc rules.

pivica’s picture

@Phil Wolstenholme this are great infos. If I understand this correctly having width and height attributes on a source tag has advantages as:

  • Your source images don't need to have the same aspect ratio for various breakpoints. With the current approach, we are forcing aspect ratio from fallback style, which is not ideal.
  • We do not polute img tag with widht and height attributes which will override usual 'width:100%;height:auto' CSS rules.

Current browsers implementation:

It seems we still need some time until all major browsers support this, so should we wait than with this?

eeyorr’s picture

Is there a chance this will be committed before Google implements Core Web Vitals ranking signals in May?

Phil Wolstenholme’s picture

@eeyorr, I think it's likely.

Acccording to https://chromestatus.com/feature/5737185317748736 it will be part of Chrome 90. The current stable Chrome release is Chrome 89.

https://www.chromestatus.com/features/schedule shows Chrome 90 as reaching a stable release around mid-April.

Edit: Sorry, I've just realised eeyorr probably means 'Will this Drupal issue be closed in time for May' whereas I thought they were asking about the change to the HTML spec that I had mentioned in an earlier comment.

Daniel Ward’s picture

Here's where I've got to on this:

  1. Agreed that using the fallback image style to set the H/W on the img tag works best.
  2. @pivica also agree it is then necessary to set width:100% and height:auto on each image in the css to maintain expected aspect ratios.
  3. @Phil Wolstenholme agreed that we should set H/W attributes on the source tag as well as img to fully support Art Direction and allow the browser to choose fully responsive images with (potentially) different aspect ratios.
  4. … although as @Phil Wolstenholme says, putting H/W in the source tag still isn’t working in Chrome 89 or Firefox 87 and we’ll have to wait for the next release to test it. I’ve created a simple codepen where you can still see janking in action: https://codepen.io/danielward99/pen/RwKjEP
  5. In preparation for Chrome 90, should we have another look at the way the module outputs picture elements…


At the moment, the responsive image module outputs each image style into a single comma-separated srcset attribute list:

<picture>
<source srcset="/sites/default/files/styles/max_325x325/public/2021-04/large.jpeg?itok=OBosLXN1 325w, /sites/default/files/styles/max_650x650/public/2021-04/large.jpeg?itok=WS4TBSbZ 650w, /sites/default/files/styles/max_1300x1300/public/2021-04/large.jpeg?itok=jt9SfiL8 1300w, /sites/default/files/styles/max_2600x2600/public/2021-04/large.jpeg?itok=0GCvKdCg 2350w" type="image/jpeg" sizes="(min-width: 1290px) 1290px, 100vw">
<img srcset="/sites/default/files/styles/max_325x325/public/2021-04/large.jpeg?itok=OBosLXN1 325w, /sites/default/files/styles/max_650x650/public/2021-04/large.jpeg?itok=WS4TBSbZ 650w, /sites/default/files/styles/max_1300x1300/public/2021-04/large.jpeg?itok=jt9SfiL8 1300w, /sites/default/files/styles/max_2600x2600/public/2021-04/large.jpeg?itok=0GCvKdCg 2350w" sizes="(min-width: 1290px) 1290px, 100vw" src="/sites/default/files/styles/wide/public/2021-04/large.jpeg?itok=2Bj04ZKZ" alt="A forest with some trees in it." typeof="foaf:Image">
</picture>


But to make it possible to set H/W on each image style in this responsive group, how about outputting a separate source tag for each breakpoint:

<picture>
        <source
            media="(max-width: 799px)"
            srcset="https://picsum.photos/1000/1500"
            type="image/jpeg"
            width="1000"
            height="1500"
        >
        <source 
            media="(min-width: 800px)"
            srcset="https://picsum.photos/2350/1500"
            type="image/jpeg"
            width="2350"
            height="1500"
        >
         <img srcset="/sites/default/files/styles/max_325x325/public/2021-04/large.jpeg?itok=OBosLXN1 325w, /sites/default/files/styles/max_650x650/public/2021-04/large.jpeg?itok=WS4TBSbZ 650w, /sites/default/files/styles/max_1300x1300/public/2021-04/large.jpeg?itok=jt9SfiL8 1300w, /sites/default/files/styles/max_2600x2600/public/2021-04/large.jpeg?itok=0GCvKdCg 2350w" sizes="(min-width: 1290px) 1290px, 100vw" src="/sites/default/files/styles/wide/public/2021-04/large.jpeg?itok=2Bj04ZKZ" alt="A forest with some trees in it." typeof="foaf:Image" width="1000" height="1500">
</picture>


I’ll have a go at a patch if this is the right approach.

Phil Wolstenholme’s picture

Hi @bingolitte,

I think there's already an option for Drupal to use multiple source elements when necessary, for example if different type values are provided.

You can see an example of that on https://api.drupal.org/api/drupal/core%21modules%21responsive_image%21re... :

<picture>
  <source [...] mime-type="image/webp" srcset="image1.webp 1x, image2.webp 2x, image3.webp 3x"/>
  <source [...] mime-type="image/jpeg" srcset="image1.jpeg 1x, image2.jpeg 2x, image3.jpeg 3x"/>
  <img src="fallback.jpeg" />
</picture>
Phil Wolstenholme’s picture

I think the srcset vs source elements with a media attribute depends on how the responsive image style is configured in Drupal, particularly around breakpoints.

The blog post linked to from this comment might be useful in explaining the configuration differences, although I admit I don't fully understand them as I always end up with a picture element with separate source elements as I use responsive images to provide WebP versions of each source.

Daniel Ward’s picture

Hi @Phil Wolstenholme,

#20 is where I started messing about with this. I think we're talking about the same blog post from ChromaticHQ. I originally followed that to get Drupal to output a picture element instead of an img tag. But for me, it defaults to a single source with multiple image styles in the srcset, rather than separate ones. Same as you, I separate my source elements out programatically in order to provide WebP support, but I don't know if there's a way to do that in the configuration.

#19 is super interesting. I need to go away and work through the helper function in more detail. It looks like it can output at least 11 combinations of picture, source and srcset, although how they all relate to the Drupal configuration...

gaëlg’s picture

Yes, you can get different aspect ratios for different viewports (art direction) through the use of different source tags.
A real life example :

<picture>
    <source srcset="/system/files/styles/3_1_lowest/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=N4-p1OFm 100w, /system/files/styles/3_1_verylow/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=R_U6uG_H 200w, /system/files/styles/3_1_low/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=AgEz9BPH 400w, /system/files/styles/3_1_medium/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=XpzI5AVQ 800w, /system/files/styles/3_1_high/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=efrF7yRT 1280w, /system/files/styles/3_1_veryhigh/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=2P2rnKGR 1440w, /system/files/styles/3_1_highest/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=Kz4L9ulL 2048w"
            media="(min-width: 768px)" type="image/jpeg" sizes="100vw">
    <source srcset="/system/files/styles/1_1_lowest/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=1njkdq9T 100w, /system/files/styles/1_1_verylow/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=RLlyttuh 200w, /system/files/styles/1_1_low/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=JaqoqRli 400w, /system/files/styles/1_1_medium/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=P8u780hB 800w, /system/files/styles/1_1_high/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=_SBv7u8M 1280w, /system/files/styles/1_1_veryhigh/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=OSknyKTT 1440w, /system/files/styles/1_1_highest/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=QU9M-sms 2048w"
            type="image/jpeg" sizes="100vw">
    <img
            src="/system/files/styles/3_1_highest/private/images/senior-couple-afternoon-tean-drinking-relax-concept-low.jpg?itok=Kz4L9ulL"
            alt="Les vertus du café" title="Les vertus du café" loading="lazy" typeof="foaf:Image" width="2048"
            height="683">
</picture>

To do that with Drupal, you must first define multiple breakpoints, usually in YOURTHEME.breakpoints.yml (https://www.drupal.org/docs/theming-drupal/working-with-breakpoints-in-d...).
Then, in the responsive image style configuration, you choose your breakpoints list in the "Breakpoint group" field. When doing so, the form is updated so that you get to configure your responsive image style for each breakpoint, i.e. each source tag.

NB: to duplicate source tags for webp support, you can use the webp contrib module.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

flyke’s picture

I just want to let people interested know that patch #10 works for me.
See attached images.

I have a project using responsive image styles with breakpoints (based on bootstrap) defined in my theme.
I was running lighthouse test in chrome on the project, noticed that it reported "Image elements do not have explicit width and height".
I applied patch #10 et voila, one less issue on the lighthouse report.

p.s. image nr 3 is named badly, it is of course lighthouse diagnostic AFTER applying the patch.
p.s.2: also works on Drupal 9.1.5 btw

Daniel Ward’s picture

Version: 9.3.x-dev » 9.2.x-dev
StatusFileSize
new1.13 KB
new3.21 KB

Patch #10 works for me to add H/W attributes to the fallback img. I've now added Patch #25 to set the H/W attributes on each source as well. It takes into account the three options in the responsive image configuration:

Where the Select a single image style. option is selected for a given breakpoint, the ouput is straightforward: only one image served up so I have used the H/W of that single styled image to determine the attributes.

Where the Select multiple image styles and use the sizes attribute. option is selected, I have used the last styled image in the breakpoint (ie: the largest image) to determine the H/W. This relies on each image in the breakpoint using the same aspect ratio, but it seems unlikely that someone would want to use different aspect ratios at the same breakpoint. In any event, providing the browser with at least one of the aspect ratios correctly is maybe than none.

Where the Do not use this breakpoint. option is selected, no source is served up at this breakpoint and the fallback img is used instead with the H/W already set by Patch #10.

glynster’s picture

@bingolitte this patch works well for a Drupal 8 project we are working on. This has always been a troublesome area especially for Lighthouse scoring. FYI we are using the img srcset only as in most cases that is the preferred vs the picture wrapper. I noticed most of the comments are related to picture and just wanted to let you know it works on img srcset as well! +1 RTBC.

Phil Wolstenholme’s picture

I just gave the patch in #25 a test run on a 8.9 and 9.1 site where we use a lot of responsive images that have separatesource elements for each type (jpeg & webp) and breakpoint - it all seemed to work well.

I had to edit my image template to get the fallback img width and height to appear as attributes, but I think that was just an issue with my theme.

I think we'll still need some more tests (see #11) to get this into core, but good work so far @bingolitte, @pivica and @nikitagupta!

vcastillo’s picture

Patch #25 is working fine for me on Drupal 8.9.15

Google search console was complaining that the Cumulative Layout Shift ( https://web.dev/cls/ ) was high on my site. This patch will help with it. Thanks!

mahtabalam’s picture

StatusFileSize
new355.61 KB

Patch #25 is working fine for me on Drupal 8.9.15

Daniel Ward’s picture

StatusFileSize
new1.01 KB
new1.57 KB
new3.93 KB

Hi all. Here's where I've got to with writing some tests for this patch:

The two key-value-pairs added by @nikitagupta in #10 to doTestResponsiveImageFieldFormatters successfully test the addition of H/W attributes to the fallback image.

I've now written two new assertions in doTestResponsiveImageFieldFormatters to test the addition of H/W attributes to the source image (patch #30).

I've run the tests as assertRaw and assertNoRaw both with an without patch #25 applied and the pass/fail results are as expected.

@Phil Wolstenholme do you think that covers with the testing requirement, or do you think it needs something else?

Phil Wolstenholme’s picture

I think if all the new functionality that has been added has a corresponding test then that's probably great, but I'm not a core maintainer or anything like that :)

gauravvvv’s picture

Patch 3192234-30.patch in #30. fixes the issue for me.
Height and width are visible now. Adding before and after patch screenshot for reference.

Patch included test and fixes the issue. Moving to RTBC.

gauravvvv’s picture

Status: Needs work » Reviewed & tested by the community
yassersamman’s picture

Status: Reviewed & tested by the community » Needs work

#30 applies cleanly, but still having issues when a page has images with no image styles, like when an image field display is set to Rendered Entity.
The issue appears here :
ImageStyle::load($responsive_image_style->getFallbackImageStyle());
So it gets null.
I don't know if there is a better solution cuz I haven't been following the issue, but I worked around it for now by checking the $image_style if null or not, and do nothing if it is.

ankithashetty’s picture

Version: 9.2.x-dev » 9.3.x-dev
Status: Needs work » Needs review
StatusFileSize
new4 KB
new1.46 KB

Updated the patch in #30 with a condition suggested by #34, thanks!

johnpitcairn’s picture

The patch at #35 seems to be working as expected for me (9.1.x).

Possible bikeshedding, but I think it hasn't been sufficiently discussed:

@bingolitte wrote:

Where the Select multiple image styles and use the sizes attribute. option is selected, I have used the last styled image in the breakpoint (ie: the largest image) to determine the H/W. This relies on each image in the breakpoint using the same aspect ratio, but it seems unlikely that someone would want to use different aspect ratios at the same breakpoint.

We have some very large sizes in our srcset attribute, to allow for large retina displays, etc. I think I would prefer the image width and height attributes to reflect the size of the fallback image, ie the style referenced in the image src attribute. That gives you an img element that would size as expected on absolutely any browser.

What is the reasoning around using the largest possible size here? If it's unlikely anyone would serve up different aspect ratios in the same srcset (though I can see use-cases for doing so), then it's also unlikely they would use a different aspect ratio for the fallback style, right?

Daniel Ward’s picture

Hi @John Pitcairn,

Assuming the images are responsive with img { width: 100%; height: auto; } set in the CSS, the images should take the width of the parent container, irrespective of the dimensions in the H/W attributes. The browser just uses H/W to calculate the aspect ratio of the expected image and reserve the correct ratio of space in the layout accordingly. In theory, we could use any reasonable numbers for the H/W attributes, so long as they return the correct aspect ratio. There's an in-depth explanation in this blog post.

In this method, I've chosen to use the largest image style only out of expedience. As long as they have the same aspect ratio, we could use any of the image styles in this breakpoint to determine the attributes. But the largest style is the last item in the responsive_image_styles array, which means we only need minimal additional code to achieve the result.

That said, if you're getting behaviours different from these, are you able to share some code snippets and screenshots?

johnpitcairn’s picture

I understand that. I was really just thinking of providing the width and height of the actual fallback src image, so the tag becomes a very standard img tag for any browsers that don't understand the srcset attribute. It seems potentially more backwards-compatible, though I have no good example so maybe it really doesn't matter. Don't consider this a blocker.

shaal made their first commit to this issue’s fork.

Daniel Ward’s picture

Hi @John Pitcairn understood now. The H\W attributes were added to the fallback image in Patch #10, but if you're seeing something different in the output, upload the screenshot and I'll take a look.

pivica’s picture

Just a heads up for people watching this issue. I found problems with the existing custom client themes and custom CSS code that is manipulating image dimensions. Usually when you have flex display applied to the image and now with new width/height attributes added image could get distorted. It happens mostly in IE11 but can happen in other modern browsers also. Nothing we can do really about this, just take a note that after adding this patch you will maybe have some additional work to fix some bugs in your custom themes.

johnpitcairn’s picture

@bingolitte: I think there may be an unforeseen consequence of using the largest responsive image size. Google's lighthouse tool is now reporting a lower performance score for the site, because it thinks there are huge images that should be resized to reduce bandwidth. I will try to confirm this in a with/without patch scenario.

Phil Wolstenholme’s picture

Another reason to use the fallback image's dimensions rather than the largest image's dimensions might be that if the CSS fails to load or is being lazyloaded and has not been loaded yet then the browser will use the width and height attributes to set the image's dimensions on the page.

In these situations, a smaller image might be less disruptive to the page than a giant one. A giant one could cause horizontal scrolling or obscure content by pushing it down quite far if we were showing a 2x resolution desktop monitor sized image to a user on a phone that went through a train tunnel just as the CSS file for the page was trying to load.

glynster’s picture

It seems even though the patch is set to use the Fallback:

$image_style = ImageStyle::load($responsive_image_style->getFallbackImageStyle());

It is not. We are getting the largest height and width set.

Now this may be due to the way in which we are using responsive image styles.

We use 1x Viewport Sizing
Select multiple image styles and use the sizes attribute.
and select all the styles

This way we are using img srcset as apposed to the picture element.

johnpitcairn’s picture

@glynster: We are doing the same.

glynster’s picture

@John Pitcairn ok good to we can replicate it. Just seems odd that the comment says:

+ // Get width and height from fallback responsive image style and transfer them
+ // to img tag so browser can do aspect ratio calculation and prevent
+ // recalculation of layout on image load.

Debugging to see what might be the cause.

glynster’s picture

StatusFileSize
new3.95 KB

Updated patch #35 to make sure the fallback is being set. @John Pitcairn can you confirm this works for you? Works on my end, was a very small tweak.

johnpitcairn’s picture

Status: Needs review » Reviewed & tested by the community

Confirmed, the patch at #47 now provides width and height attributes from the fallback image when using the srcset attribute for an <img> element. Thanks @glynster.

larowlan’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Bug Smash Initiative
  1. +++ b/core/modules/responsive_image/responsive_image.module
    @@ -212,6 +212,26 @@ function template_preprocess_responsive_image(&$variables) {
    +  // We are assuming that all image styles in this responsive image have the
    +  // same aspect ratio.
    

    This feels like a pretty big assumption

    Isn't the whole point of responsive design and the responsive image supposed to be that you serve the best image resolution for the breakpoint? What are the implications here?

  2. +++ b/core/modules/responsive_image/responsive_image.module
    @@ -212,6 +212,26 @@ function template_preprocess_responsive_image(&$variables) {
    +    if (!file_exists($build_uri)) {
    +      $image_style->createDerivative($variables['uri'], $build_uri);
    

    We can't go doing this in a preprocess function. See \Drupal\image\Controller\ImageStyleDownloadController::deliver we have a whole lock system wrapped around image-style generation to prevent race conditions between multiple threads.

    Doing it here means we're bypassing all of that stampede protection. I think we're going to need to think about what happens here when the image doesn't exist and the server is under concurrent load.

catch’s picture

+++ b/core/modules/responsive_image/responsive_image.module
@@ -212,6 +212,26 @@ function template_preprocess_responsive_image(&$variables) {
+    $build_uri = $image_style->buildUri($variables['uri']);

Agreed with @larowlan about the file i/o here - we have image styles specifically to avoid doing anything in actual page requests.

What about using ImageStyle::transformDimensions() here? That should have the same effect without any major overhead.

I also have the same question about what happens if the height and width are wrong - will it be corrected (requires a recalculation, but we already have one) when the image is actually loaded or are we risking displaying the image in the wrong aspect ratio?

glynster’s picture

@larowlan @catch you are both right here. The patch is assuming and hooking in after the fact. My knowledge is limited and I just worked off the proposed patch. For me the patch has been useful for lighthouse scoring and best practices for images to have a width and height set.

johnpitcairn’s picture

I guess this means there is no way to sensibly set those attributes in the html source for an image srcset, unless you make the assumption that the aspect ratio does not change.

There are definitely sites I've built where the aspect ratio of images does change at different breakpoints - though for that I wouldn't use srcset.

Phil Wolstenholme’s picture

I wrote some custom code in a theme a few weeks ago that loops through all the widths and heights and checks that they are the same aspect ratio (or close enough, to account for human errors when configuring each image style width and height). Maybe we could use something like that to check the aspect ratios and ensure they're the same for each breakpoint?

Another thing to discuss is if it matters too much if we do accidentally set incorrect width and height attribute values in some cases? My understanding is that once the image has loaded then incredibly common CSS rules like img { width: 100%; height: auto; } would mean that the image attributes would get ignored anyway. The attributes are most useful for preventing layout shift issues as an unloaded image takes up no space. If we provided incorrect width and height attributes then there would still be some layout shift, but not as much as if we provided no width or height attributes at all. But as long as that CSS snippet is on the site then I don't think we'd end up with distorted images, as the CSS would override the attribute values.

johnpitcairn’s picture

Maybe responsive image module should supply that css by default?

Phil Wolstenholme’s picture

I got my CSS snippet a bit wrong earlier, it's this one that many people use:

img {
  max-width: 100%;
  height: auto;
}

I just checked and Bartik, Claro, Seven, and the Umami theme all include it. However the max-width vs width distinction is important and might mean that some of the info in my last comment about the CSS overriding the width attribute is wrong unfortunately, sorry about that everyone.

maximpodorov’s picture

Status: Needs work » Needs review
StatusFileSize
new3.99 KB
new2.53 KB

The patch with transformDimensions() instead of createDerivative().
Dimensions are output for <source> tags if possible.

jeni_dc’s picture

Just tested the patch from #56 on a D8 site I'm trying to get better PageSpeed scores on. Patch applied cleanly on 8.9.16, width and height are output as expected, and Google has stopped complaining about the missing width and height.

Worth noting this site only has one image style defined for use with WebP so all srcset images and the fallback have the same dimensions.

rar9’s picture

Patch 56 applied nice but for responsive images Firefox and Safari read them wrong.

Firefox and Safari are using width and height form < img part of picture instead of < source
Chrome and resend Edge do it right and use < source width and height.

Any solution for this?

berdir’s picture

StatusFileSize
new4.11 KB

Reroll for 9.3.x. This won't apply on 9.2 anymore.

luke.leber’s picture

Status: Needs review » Needs work

Is there any concern that adding loading="lazy" to an image that happens to be the LCP element will cause such an image to be prioritized lower than usual? I'm not quite sure how to definitively benchmark this, but it seems at least in Chrome 81, that adding the loading attribute causes an LCP image to be loaded at position #25 as opposed to position #15 on an arbitrary Drupal 9 site that I just tested it out on. A pile of non-lazy SVG images seem to be prioritized and downloaded first...which is not what we would want for LCP performance.

Theoretically, LCP images should be eagerly loaded in order to cause the FCP timing to happen as early as possible.

I'm going to set this back to "Needs Work" until someone can either confirm or dismiss my concerns. If this is indeed the case, then I think that we'll have to make a toggle for this on a per-image-style basis.

Thanks.

Phil Wolstenholme’s picture

@Luke, I don't think this patch does anything relating to the `loading` attribute, it just adds `width` and `height` attributes.

The lazy loading attribute comes from https://www.drupal.org/project/drupal/issues/3167034. You're right about lazyloading not always being the right choice and having an impact on LCP for hero images, which is why there is an issue (https://www.drupal.org/project/drupal/issues/3173180) to add a UI to be able to turn it on and off.

luke.leber’s picture

@Phil - I can understand that the patch doesn't directly add 'lazy', but indirectly it does cause the attribute to be applied to images generated by responsive image formatters.

Functionally, this patch, as it stands, could have a detrimental impact on quite a few sites unless I'm missing something obvious?

At any rate, I think that blocking this task until the UI lands is a smart move. A warning in the I.S. might also be useful to prevent people from applying this patch without taking the proper benchmarking steps, which in my experience is a lot more effort than most folks are willing to go through :). Our LCP went up by ~400ms when applying this patch.

luke.leber’s picture

On a good note, it is very easy to rectify the performance hit, should any adventurous shops want to give it a try.

/**
 * Implements template_preprocess_responsive_image().
 */
function MY_THEME_preprocess_responsive_image(&$variables) {

  $eager_styles = [
    'hero_banner_style_1',
    'hero_banner_style_2',
  ];

  if (in_array($variables['responsive_image_style_id'], $eager_styles, TRUE)) {
    $variables['img_element']['#attributes']['loading'] = 'eager';
  }

}
Phil Wolstenholme’s picture

@Luke, ah yes, of course - Core won't add the native lazy loading unless the image has a width and height set, and this patch adds a width and height for responsive images, so now they'll be made to load lazily, I get it now.

Personally, I'm not sure the performance issue should block this issue though, it didn't block https://www.drupal.org/project/drupal/issues/3167034 which did the same thing for non-responsive images?

https://www.drupal.org/project/drupal/issues/3173180 has some discussion around adding the UI to the responsive image formatter, which is good.

luke.leber’s picture

The more that I think about it, I keep coming back to the fact that #3167034 may have introduced a performance regression and that the UI work should be promoted to a major issue.

Given that #3167034 was closed out 9 months ago, it is reasonable to conclude that core web vitals wasn't on anyone's radar at the time.

Performance really is a tricky beast to tackle.

Daniel Ward’s picture

Phil Wolstenholme’s picture

I've just seen Rar9's comment:

Patch 56 applied nice but for responsive images Firefox and Safari read them wrong.

Firefox and Safari are using width and height form < img part of picture instead of < source
Chrome and resend Edge do it right and use < source width and height.

Any solution for this?

At the moment using the width and height attributes from the source elements is a Chromium only feature.

There is a Firefox bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=1694741
And a Safari bug here: https://bugs.webkit.org/show_bug.cgi?id=222368

Fingers crossed all browsers support this eventually!

Phil Wolstenholme’s picture

Status: Needs work » Needs review

Given that we have #3173180: Add UI for 'loading' html attribute to images to eventually toggle the lazyloading behaviour and a workaround in comment #63, I don't think this issue (which is mostly concerned with fixing CLS issues) should be in 'needs work' because of its interaction with the lazyloading behaviour. That said, I am happy to be disagreed with :)

I agree that it is really important to be able to turn off lazyloading for big images to prevent LCP issues, but I think the place to help push for that change is in #3173180: Add UI for 'loading' html attribute to images, and this issue should focus on the CLS (holding space for images by setting width and height attributes) issue.

Phil Wolstenholme’s picture

StatusFileSize
new65.96 KB

I think I've found an issue with #59 when using the 'Select a single image style for each breakpoint approach' and when using a 1x and 2x multiplier.

On line 42 of the patch we check to see if count($srcset) === 1:

+  if (count($srcset) === 1 && !empty($dimensions['width']) && !empty($dimensions['height'])) {
+    $source_attributes->setAttribute('width', $dimensions['width']);
+    $source_attributes->setAttribute('height', $dimensions['height']);
+  }

In my case this check failed as count($srcset) was equal to 2 – one entry for the 1x multiplier and one entry for the 2x multiplier:

Screenshot showing two entries in the $srcset array

I'm not sure what the best fix is here. What was the purpose of the count($srcset) === 1 check? Could we replace it with count($srcset) > 0? Or maybe (count($srcset) === 1 | $image_style_mapping['image_mapping_type'] == 'image_style')?

Phil Wolstenholme’s picture

StatusFileSize
new4.22 KB

I'm not sure this is the best approach, but here is a patch that swaps count($srcset) === 1 for (count($srcset) === 1 | $image_style_mapping['image_mapping_type'] == 'image_style').

I have tested this with a responsive image style using the 'Select a single image style for each breakpoint approach' and using a 1x and 2x multiplier, but I've not tested it with the 'sizes' approach.

Edit: I've noticed my changes mean that the dimensions are coming from the 2x multiplier so they are double what they would be for the 1x modifier, but they still do the job of setting a correct aspect ratio. There's probably something nicer we can do here to avoid this.

Sorry for the lack of an interdiff, patchutils gave me a interdiff: Whitespace damage detected in input message and produced an empty interdiff when I tried to use it.

longwave’s picture

+++ b/core/modules/responsive_image/responsive_image.module
@@ -421,6 +432,10 @@ function _responsive_image_build_source_attributes(array $variables, BreakpointI
+  if ((count($srcset) === 1 | $image_style_mapping['image_mapping_type'] == 'image_style') && !empty($dimensions['width']) && !empty($dimensions['height'])) {

I think | should be || here.

Phil Wolstenholme’s picture

StatusFileSize
new8.55 KB

Thanks @longwave.

I was in a bit of a rush - here's a revised patch that uses ||. I think I'll step away from this issue for a bit and work on something else to avoid making any more silly mistakes :)

Phil Wolstenholme’s picture

StatusFileSize
new4.22 KB

…and here's another revised version where the patch doesn't contain a previous patch that I accidentally included in the git diff that I used to make the patch! 🤦‍♂️

ahmad abbad’s picture

StatusFileSize
new2.49 KB

Reroll patch Core 9.2.5

Status: Needs review » Needs work

The last submitted patch, 74: 3192234-74.patch, failed testing. View results

vsujeetkumar’s picture

Status: Needs work » Needs review
StatusFileSize
new4.18 KB
new1.5 KB

Due to some missing changes in #74, tests is fail. Added a patch with all the changes, Please have a look.

rar9’s picture

#76 wont apply for 9.2.x , so for now will continue with #56

Daniel Ward’s picture

qusai taha’s picture

StatusFileSize
new3.56 KB

I edited patch #76 to fix the HTML validation errors:
Error: Attribute height is not allowed on the element source at this point.
Error: Attribute width not allowed on element source at this point.
so no need for width and height on the source tag.

qusai taha’s picture

StatusFileSize
new3.62 KB
qusai taha’s picture

StatusFileSize
new3.56 KB
rar9’s picture

Thanks #81 works nicely on d9.2.6

maximpodorov’s picture

Unfortunately, patches #79 - #81 contradict the very soul of this task: to add attributes which help browsers to reserve proper space for not yet loaded images. Modern browsers start to support these attributes for source element.

yogeshmpawar’s picture

StatusFileSize
new3.68 KB

Straight re-roll for #81 on 9.3.x branch.

devkinetic’s picture

StatusFileSize
new4.22 KB
new718 bytes

Here is a reroll of #84, with the source attributes added back in per the comment in #83 for 9.3.x.

ambient.impact’s picture

#83: It would be helpful to get links to various browser vendors' intentions on this subject before adding width and height attributes to <source> elements so that we know exactly how they're going to interpret them.

chetanbharambe’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new891.05 KB
new967.74 KB

Verified and tested patch #85.
Patch applied successfully and looks good to me.

Testing Steps:
# Goto: Appearance -> Apply Seven theme
# Goto: Extend -> Install "Responsive Image" module
# Goto: admin/structure/types/manage/page/fields
# Add Image field
# Goto: admin/structure/types/manage/page/display
# Select "Responsive Image" under format
# Upade it
# Create respective content type with image where user added the image field
# Save it
# Inspect element and goto on that uploaded image
# Check the results.

Expected Results:
# After applying patch #85, the User should see Width and Height attributes appearing for the responsive image tags.

Actual Results:
# Width and Height attributes are not appearing for the responsive image tags.

Please refer attached screenshots for the same.
Looks good to me.
Can be a move to RTBC.

longwave’s picture

Re #83/86 width and height attributes on the source element is part of the HTML5 spec:

Relevant quotes from https://html.spec.whatwg.org/multipage/embedded-content.html#the-source-...

The source element's parent is a picture element
...
The source element supports dimension attributes. The img element can use the width and height attributes of a source element, instead of those on the img element itself, to determine its rendered dimensions and aspect-ratio.
...
The width and height attributes on an img element's dimension attribute source map to the dimension properties 'width' and 'height' on the img element respectively. They similarly map to the aspect-ratio property (using dimension rules) of the img element.

To me this implies that conforming browsers should use the width/height found on source to replace the width/height on img when rendering responsive images.

mariacha1’s picture

Status: Reviewed & tested by the community » Needs work

The patch at #85 only works if your responsive image sources all have the same aspect ratio, which matches the fallback img ratio.

This comment is still true: https://www.drupal.org/project/drupal/issues/3192234#comment-14220803 -- the last patch that accomplished the goal of this ticket was in #76.

ambient.impact’s picture

#88 That's what I was looking for, thanks!

heddn’s picture

Issue summary: View changes

Updating IS. I think we need a decision on where we want to put the dimensions.

heddn’s picture

Issue summary: View changes
heddn’s picture

I've removed the responsive image implementation of lazy loading from #3173180: Add UI for 'loading' html attribute to images so as to move that into here. This way we can add dimensions at the same time we add lazy loading support. Or if that gets too complicated in _this_ issue, we can land dimensions first and lazy loading with a UI toggle as a follow-up. Although I think the lesson learned from hard coding loading="lazy" first time around for <img> was that it caused negatively affects to the page's LCP score. So I think I would advocate for doing enabling lazy loading and a UI to disable it (loading: eager) all at the same time.

rar9’s picture

What patch to use with Drupal 9.27?
#81, #84 or #85 are no longer working

heddn’s picture

Title: Apply width and height attributes to responsive image tag » Apply width and height attributes to allow responsive image tag use loading="lazy"
Issue summary: View changes

Re-titling.

heddn’s picture

Issue summary: View changes
heddn’s picture

Category: Bug report » Task
Issue summary: View changes
heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new24.91 KB
new21.3 KB

OK, this (hopefully) makes things a little more happy. This adds dimensions to the <source> and <img> tags. For browsers that support it, they should leverage the sizes on the <source> tag in favor over <img>. This also adds the field formatter changes from #3173180: Add UI for 'loading' html attribute to images that are appropriate to responsive image. And adds update tests for both field formatter and views fields.

This could use some reviews at this point. I still want to beef up test coverage of dimensions added to the <source> tags, but there is enough working code here that a review would beneficial.

Sorry for such a lot of changes. If you are at all familiar w/ the latest patches in #3173180: Add UI for 'loading' html attribute to images, then the review should be pretty easy here as there's wide copy/paste between these 2 issues. Perhaps that means we should create a trait? I'm not sure.

rar9’s picture

#98 Still wont apply to 9.27 :-(

ambient.impact’s picture

@Rar9: I'm seeing this error too with the previously working patch from #56 (haven't tried newer ones). I ran composer update drupal/core* --verbose and it looks like it's failing on ResponsiveImageFieldDisplayTest.php, but the rest patches okay:

    https://www.drupal.org/files/issues/2021-06-23/3192234-56.patch (Apply width and height attributes to responsive image tag (core 9.2.x) #3192234: Apply width and height attributes to allow responsive image tag use loading="lazy": https://www.drupal.org/project/drupal/issues/3192234 )
patch "-p2" --no-backup-if-mismatch -d "drupal/core" < "C:\Users\i\AppData\Local\Temp/615f017ceae36.patch"
patching file modules/responsive_image/responsive_image.module
patching file modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php
Hunk #1 FAILED at 309.
1 out of 2 hunks FAILED -- saving rejects to file modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php.rej
devkinetic’s picture

@Rar9 this issue is for 9.3.x if you need this for 9.2.x you'd have to backport the latest patch.

heddn’s picture

Issue tags: -Needs tests
StatusFileSize
new4.06 KB
new26.79 KB

re: applying on 9.2. There are some test only changes in 9.3 that makes the patch here fail to apply on 9.2. I recommend you create a patch without tests and include that local patchfile in your development workflow instead.

Here's some test coverage and a small fix to the formatter. Removing the needs tests tag. I marked this earlier as a task, without a comment. But that is really what we have here. Work that needs to be done. There's no bug per-se.

ambient.impact’s picture

StatusFileSize
new2.42 KB

@Rar9 Here's #56 with the test removed as per @heddn's suggestion. It applied without errors on 9.2.7 for me.

heddn’s picture

StatusFileSize
new3.06 KB
new26.72 KB
qusai taha’s picture

StatusFileSize
new17.31 KB

Re-roll patch to drupal 9.2.7

heddn’s picture

StatusFileSize
new26.72 KB

The last uploaded patch needs to be for 9.3. If we upload another patch for another branch, please also include the 9.3 patch too. Otherwise the testbot can't run tests and keep the most recent patch front and center for reviewing.

Re-uploading #103.

heddn’s picture

Issue summary: View changes
StatusFileSize
new27.4 KB
new1.63 KB

Updated comment and implementation on when to add dimensions to the srcset. Feedback requested.

heddn’s picture

StatusFileSize
new8.38 KB
new33.74 KB

Some more docs updates.

yogeshmpawar’s picture

StatusFileSize
new33.74 KB
new3.55 KB

Resolved custom commands failure & also added an interdiff for review.

yogeshmpawar’s picture

StatusFileSize
new434.82 KB

.

smustgrave’s picture

Is this patch suppose to add a UI for setting width/height when embedding a media?

johnpitcairn’s picture

No.

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC - After extensive review this patch looks great to me.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 109: 3192234-109.patch, failed testing. View results

longwave’s picture

  1. +++ b/core/modules/responsive_image/config/schema/responsive_image.schema.yml
    @@ -67,3 +67,10 @@ field.formatter.settings.responsive_image:
    +    image_loading:
    +      type: mapping
    +      label: 'Image loading settings'
    +      mapping:
    +        attribute:
    +          type: string
    +          label: 'Loading attribute'
    

    Why do we need a parent and child key here? Do we expect to add more items under "image_loading"?

  2. +++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
    @@ -186,7 +212,12 @@ public function settingsSummary() {
    +    $summary[] = $this->t('Loading attribute: @attribute', [
    

    The test failure shows that we weren't testing this summary. Should we also test the summary when it's set to eager?

  3. +++ b/core/modules/responsive_image/tests/src/Functional/ResponsiveImageFieldDisplayTest.php
    @@ -318,6 +318,10 @@ protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles =
    +      // Assert the output of the 'width' attribute.
    +      $this->assertSession()->responseContains('width="360"');
    +      // Assert the output of the 'height' attribute.
    +      $this->assertSession()->responseContains('height="240"');
    

    Should we test the loading attribute here?

  4. +++ b/core/modules/views/src/ViewsConfigUpdater.php
    @@ -480,6 +480,50 @@ protected function mapOperatorFromSingleToMultiple($single_operator) {
    +  protected function processReponsiveImageLazyLoadFieldHandler(array &$handler, string $handler_type, ViewEntityInterface $view) {
    

    Reponsive -> Responsive (should cspell have caught this?)

heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new3.3 KB
new34.8 KB

115.1: I don't think there will be more later. But to handle testing the upgrade path in ResponsiveImageLazyLoadUpdateTest and the way that entity view displays inject their default settings, it gets a lot more complicated to test this thing. Is there a strong reason _not_ have the nesting?
115.2: We have a functional test of both eager and lazy already.
115.3: Done
115.4: Fixed

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

luke.leber’s picture

StatusFileSize
new4.06 KB

Just a re-roll of #56 to apply to the latest Drupal 9.2.x (seems folks are looking for a patch that'll apply to 9.2.x, but there isn't one available in this issue anymore).

Hope to see this issue committed soon :-).

maxmendez’s picture

Installed and tested patch #116 under Drupal 9.3.0 and seems to work correctly. Thanks for the effort.

glynster’s picture

@MaxMendez we have also tested patch #116 using Drupal 9.3.0 and works correctly. RTBC +1.

pivica’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new35.73 KB
new1.84 KB

I've stumbled on a problem while testing latest patch. Situation is the next one, we are using 'sizes' option for responsive images and selected breakpoint group is 'Responsive Image' - meaning we are using img.srcset and not picture tag. For the fallback image style we have 'Content Image (LG)' style with a rule 'Scale width 1640' - so image should be 1640px width for this image style.

Now when doing a test with a latest patch (from #116) I am getting next html code for this responsive image:

<img loading="lazy" srcset="/sites/default/files/styles/primer_content_xs/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=0V6irWqH 461w, /sites/default/files/styles/primer_content_sm/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=FWfJBW-a 800w, /sites/default/files/styles/primer_content_md/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=AuINY16C 1200w, /sites/default/files/styles/primer_content_lg/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=Nej_jXEw 1640w, /sites/default/files/styles/primer_content_xl/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=mMOrA2De 1920w" sizes="(min-width:1366px) 1332px, (min-width:992px) 930px, (min-width:768px) 690px, (min-width:576px) 510px, calc(100vw-30px)" width="461" height="346" src="/sites/default/files/styles/primer_content_lg/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=Nej_jXEw" alt="building" class="img-fluid">

Note width and height attributes value `width="461" height="346"` which is wrong, width should be picked from fallback image style and its value should be 1640.

I've done a lot of debugging to figure why this is happening and here is explanation why the width/height are not correct:

In `template_preprocess_responsive_image()` on line 173 we have

$variables['sources'][] = _responsive_image_build_source_attributes($variables, $breakpoints[$breakpoint_id], $multipliers);

And _responsive_image_build_source_attributes() will set also width and height source attributes - but do note that this width and height are taken from the last image styles, meaning width and height you are getting from this depends on your image styles and also its order!

Right bellow above code is this:

if (isset($variables['sources']) && count($variables['sources']) === 1 && !isset($variables['sources'][0]['media'])) {
    // There is only one source tag with an empty media attribute. This means
    // we can output an image tag with the srcset attribute instead of a
    // picture tag.
    $variables['output_image_tag'] = TRUE;
    foreach ($variables['sources'][0] as $attribute => $value) {
      if ($attribute != 'type') {
        $variables['attributes'][$attribute] = $value;
      }
    }

Which will transfer source attributes, including width and height, to $variables['attributes']. Note that this are width and height picked from last image style and not the fallback image style width and height.

In the same function on the end this code:

if (isset($variables['width'], $variables['height'])) {
    $dimensions = responsive_image_get_image_dimensions($responsive_image_style->getFallbackImageStyle(), ['width' => $variables['width'], 'height' => $variables['height']], $variables['uri']);
    $variables['img_element']['#width'] = $dimensions['width'];
    $variables['img_element']['#height'] = $dimensions['height'];
}

will set width and height dimensions from fallback style but on the $variables['img_element'] element.

Finally, in `template_preprocess_image()` function next code is responsible for bringing fallback image style width and height from variables into attributes,

foreach (['width', 'height', 'alt', 'title', 'sizes'] as $key) {
    if (isset($variables[$key])) {
      // If the property has already been defined in the attributes,
      // do not override, including NULL.
      if (AttributeHelper::attributeExists($key, $variables['attributes'])) {
        continue;
      }
      $variables['attributes'][$key] = $variables[$key];
    }
}

but in this case it will not work because attributes already have wrong width and height from responsive last image style so correct width and height from fallback style will never be used.

I've tracked patch changes in comments and found out that in comment #70 @Phil Wolstenholme introduced next change

+++ b/core/modules/responsive_image/responsive_image.module
@@ -421,6 +432,10 @@ function _responsive_image_build_source_attributes(array $variables, BreakpointI
+  if ((count($srcset) === 1 | $image_style_mapping['image_mapping_type'] == 'image_style') && !empty($dimensions['width']) && !empty($dimensions['height'])) {
+    $source_attributes->setAttribute('width', $dimensions['width']);
+    $source_attributes->setAttribute('height', $dimensions['height']);
+  }

With this code our test case will work correctly. Then @heddn in #107 removed second part of if statement:

+++ b/core/modules/responsive_image/responsive_image.module
@@ -432,7 +432,18 @@ function _responsive_image_build_source_attributes(array $variables, BreakpointI
-  if (!empty($dimensions['width']) && !empty($dimensions['height']) && (count($srcset) === 1 || $image_style_mapping['image_mapping_type'] === 'image_style')) {
...
+  if (!empty($dimensions['width']) && !empty($dimensions['height'])) {

Why is second part of condition removed in this change, #107 is not explaining this?

That missing second condition is the reason our test is failing.

Here is a new patch that is fixing this (it applies to 9.3.x and 9.4.x). But instead of bringing back that missing condition I am just setting width and height on img_elements attributes instead of adding width and height variables, because attributes are stronger later in preprocessor. Testing with this patch both picture tag and image with srcset looks good now.

pivica’s picture

Just to clarify why wrong width/height are a problem. The aspect ratio is the same but most of the time you will use CSS like

img {
  max-width: 100%;
  height: auto;
}

And if width/height attributes are small, then image will not fill desired area and will be smaller then maximum width of it parent wrapper.

Following this, should we change 'Fallback image style' field description on responsive image style admin UI? Currently it is saying:

Select the smallest image style you expect to appear in this space. The fallback image style should only appear on the site if an error occurs.

And this is not correct any more now when we are injecting width and height attributes because if you select smallest image style which is smaller then your parent wrapper where you are putting your image and if you have above regular CSS rule for image then image will be smaller then you would actually want it to be. Description should recommend something like - select image style which is bigger or same size as your maximum width of parent wrapper of an image on the page.

This all applies for image srcset, not sure is the same problem is happening for picture tag because there fallback image is used only if browser is not supporting picture tag.

pivica’s picture

StatusFileSize
new35.73 KB

Fixed PHPCBF error.

Status: Needs review » Needs work

The last submitted patch, 124: 3192234-124.patch, failed testing. View results

tregonia’s picture

Implemented #119 today and the patch applies, but I am not finding any height and width attributes on the <source> elements. Digging through the comments, I suspect that some of the points made in #123 are valid for the patch for 9.2.x, and the reason that the attributes are not present.

heddn’s picture

@pivica, great find! In your research of the problem, did you find if this was a browser specific issue? From reading https://www.smashingmagazine.com/2020/03/setting-height-width-images-imp..., I get the distinct impression that the fallback image and its size should only be used in a fallback scenario.

I hope it is browser or fallback specific. Because if it isn't, we might need to go back to the drawing board a bit. We don't really want to set a fallback image that is large. That would mean all the poor mobile users with old cell phones on slow data networks will have to download large images. But we also don't want to set the dimensions on that fallback image to the large size with a tiny image. That would lead to bad experience for those same poor users.

pivica’s picture

Status: Needs work » Needs review
StatusFileSize
new14.17 KB
new318.01 KB
new981.73 KB
new35.84 KB
new2.6 KB

> @pivica, great find! In your research of the problem, did you find if this was a browser specific issue?

This happens both in FF and Chrome and I guess it should happen also in other browsers. I don't think it is a browser bug, basically we are setting width and height of an image that is smaller then parent and then image can't expand properly.

Here are couple of screenshots that are explaining situation.

First with a patch from #116 image is still not loaded:

I've added red outline so we can visualize image dimension. You can see that image is not filling its parent. Then when image is loaded no layout changes, image is still with smaller dimensions then it should be:

With a proposed changes in #122 image is now filling the whole parent space horizontally:

In our case the problem is that instead of using width and height from fallback image style, code is using image style dimension from last used image style which just happened to be small so you can easily spot the bug visually.

Checking the html generated code, in our test case, instead of

<img loading="lazy" srcset="..." width="461" height="161" src="/sites/default/files/styles/primer_content_lg/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=Nej_jXEw" alt="building" class="img-fluid">

where width=461 and height=161 are from smallest image style output should be:

<img loading="lazy" srcset="..." width="1200" height="419" src="/sites/default/files/styles/primer_content_lg/public/2017-05/architecture-1048092_1920_1_44.jpg?itok=Nej_jXEw" alt="building" class="img-fluid">

where width=1200 and height=419 are from fallback image style.

Last patch has some test fail problems and the problem is that order of attributes is changing. This is a bit tricky to solve so i've reverted code that were setting width and height and unset width and height values that are making problems. Not sure is this the best approach but the tests should be green now.

pivica’s picture

StatusFileSize
new35.61 KB
new519 bytes

Removed not needed use statement.

benmorss’s picture

I'm asking a few folks to see if they have an opinion on the best thing to do here - or whether some other CMS implements a best practice that could be adopted here. Unfortunately a lot of people are still on vacation, so I might not get a great answer until next week...

One thing I wanted to clarify, as I'm not familiar with image size options in Drupal... only browsers that don't support srcset would use this fallback image. (I think that's just IE and Opera Mini.) From what you're saying here, the various sizes specified in srcset wouldn't necessarily share the same dimension ratio... is that right? In that case, is there ever a fallback image that you could be sure would be the right dimensions, and thus expand to the proper size?

In other words, would the fallback image often be in the wrong aspect ratio anyway?

pivica’s picture

@benmorss if you have a need for a different aspect ratios for different screen sizes then you should use a picture element and not img element with srcset. Browsers are adding support for width and height attributes for picture source elements and with this it does not matter which fallback image you choose in this case because browser does not need a fallback image width and height to figure correct aspect ratio to show picture image.

This patch is also adding support for picture width and height attributes. You can use it in Drupal if you use responsive image style breakpoint group with multiple breakpoints.

The last discussion we are having is more about img srcset responsive image usage because browser is then using width and height of img element and we need to have correct values there which should be picked from fallback image which you can configure.

zenkul’s picture

#129
worked,
thank you very much

benmorss’s picture

@pivica perhaps I misunderstood the issue you're describing in #128. I thought you were pointing out that, when the browser expanded the small fallback image, blank space was left because it had a different height/width ratio than the container. I think now that you were not saying that all :)

You were just saying that the small image looked lousy when expanded to a larger container. Which can certainly be the case. If dimensions are consistent among the generated images, then this problem is solved if the fallback image is the largest size, not the smallest. Except that users who are using IE (or especially Opera Mini), which don't support srcset, might well also be more likely to use slower connections, on which the larger image can be an unnecessary hardship if it's being displayed in a smaller container after all.

Do I understand the issue correctly?

pivica’s picture

> You were just saying that the small image looked lousy when expanded to a larger container. Which can certainly be the case.

Not exactly, the problem I detected was the next one. Added code was picking width and height values from the last image instead of using a fallback image. In our case it happened that the last image in responsive image style was also the smallest image so width and height from the smallest images were applied to img.srcset. As a result the img.srcset element was not able to expand to it natural dimensions (what ever that dimension is based on screen size and img.srcset values) because it was limited with small width and height attributes.
There were no expansions but the big image on big screen was cramped because width attribute value was from small image.

So if you are going to use img.srcset instead of picture element then you should make sure that your fallback image is larger then the largest possible responsive area it can hold. The code change I did in #128 is doing just that - ensuring that width and height values from fallback image are used for your img.srcset element.

I hope I explained this time better?

> Except that users who are using IE (or especially Opera Mini), which don't support srcset, might well also be more likely to use slower connections, on which the larger image can be an unnecessary hardship if it's being displayed in a smaller container after all.

In this case IE will just use img.src fallback image url to load the image, and it will load what ever you configure to use for a fallback image. The image should still look good if you use correct fallback image (with large enough dimensions for your use case).

heddn’s picture

@pivica, I think where Ben and I are getting stumped up is

Following this, should we change 'Fallback image style' field description on responsive image style admin UI? Currently it is saying:

Select the smallest image style you expect to appear in this space. The fallback image style should only appear on the site if an error occurs.

And this is not correct any more now when we are injecting width and height attributes because if you select smallest image style which is smaller then your parent wrapper where you are putting your image and if you have above regular CSS rule for image then image will be smaller then you would actually want it to be. Description should recommend something like - select image style which is bigger or same size as your maximum width of parent wrapper of an image on the page.

If we are supposed to change to a larger image, doesn't this impact the very users we want to support? The users that can't handle <img srcset=""/>? Although from looking at https://caniuse.com/srcset, the sites that can't handle srcset are very few.

heddn’s picture

Hmm, what if we don't set the image width/height on the <img/> tag? That would result in layout shift, but would it only be for the fallback image? Meaning, not for the 95% of browser users that support <img srcset=""/>.

heddn’s picture

Re #136: I don't think that will work. We are better off updating the wording of the fallback image. Or, just "do the right thing". I think the "right thing" in this case is to use the largest image size (first image) for the height/width on the <img> tag. In those cases where we aren't using <picture>

pivica’s picture

> @pivica, I think where Ben and I are getting stumped up is

Yes, I agree this description needs to change now if we are going to implement proposed changes and keep width and height attributes for img.srcset case.

> Hmm, what if we don't set the image width/height on the <img/> tag? That would result in layout shift, but would it only be for the fallback image?

No that width and height values are shared for both fallback image and srcset images so it will affect the whole image no matter what browser decide to load. So i don't think we can solve it by removing width and height. Also Chrome Lighthouse and others testing tools will start to complain, not sure can this affect SEO scoring also, possibly because Lighthouse does not like layout shifts.

> I think the "right thing" in this case is to use the largest image size (first image) for the height/width on the <img> tag.

Agree, maybe somebody with native English knowledge can propose correct wording for this?

benmorss’s picture

Just noting, as per conversation just now with @heddn, that Opera Mini is widely used in Africa on mobile devices.

According to https://gs.statcounter.com/browser-market-share/mobile/africa , it's got a 12% market share on mobile devices. Lots of these users will be facing 2G or sub-2G bandwidth and/or data restrictions. So it would be nice to serve them smaller images by default.

On the other hand, IE users are of course likely to be on desktop devices, where large images would be fine :)

I might also guess that Drupal sites are somewhat more likely to be used on desktop devices than the average site... so that would tilt the scales back in favor of serving the largest image. Which, from the discussion here, sounds like what needs to be done anyway.

johnpitcairn’s picture

Whether the fallback image should be large, small, the same aspect ratio or otherwise is a decision for the designer and site-builder, based on known or assumed metrics about the site's intended user base, the theme breakpoints in use, and how those apply to the layout. A larger screen does not always equal larger images. This should not be baked into core (or core help text) as an assumption.

Conflating the fallback image dimensions with the image element width and height attributes is possibly not optimal as a result. A better mechanism could be proposed, but once again it should be a decision for the designer and site-builder. This might be to optionally allow separately selecting a style to provide the size attributes, or providing two integer fields to allow an optional manual override, etc.

Might this be best addressed as a follow-up issue?

pivica’s picture

> Whether the fallback image should be large, small, the same aspect ratio or otherwise is a decision for the designer and site-builder...

Let's just not forget that if serving a large fallback image for img.srcset is a problem for your site (or different aspect ratio) you can always switch to picture element where you will not have this problem because with picture element you are free to select what ever fallback image style you want - this will not affect picture element because each source element has it's own correct width and height.

So I think that we don't need to add more configuration complexity to img.srcset responsive image - this is a simpler responsive image solution, and if you need more control you should switch to picture responsive image solution.

heddn’s picture

Issue summary: View changes
Status: Needs review » Needs work
StatusFileSize
new15.68 KB

NW to implement #137/#138.

Some possible language for the fallback description:

Select the image style you wish to use as the style when a browser does not support responsive images.

fallback language

catch’s picture

According to https://gs.statcounter.com/browser-market-share/mobile/africa , it's got a 12% market share on mobile devices. Lots of these users will be facing 2G or sub-2G bandwidth and/or data restrictions. So it would be nice to serve them smaller images by default.

On the other hand, IE users are of course likely to be on desktop devices, where large images would be fine :)

We're officially dropping IE support in Drupal 10, but not support for Opera mini, so that puts a bit more weight on using the lowest bandwidth option for the fallback. I also don't think it hurts to default to the lower bandwidth option in Drupal 9 where we support both - IE users have a lot of options compared to a phone on 2g/3g and at worst they get a little image instead of a page that never finishes loading.

pivica’s picture

> We're officially dropping IE support in Drupal 10, but not support for Opera mini, so that puts a bit more weight on using the lowest bandwidth option for the fallback.

That should be still fine, site admin/builder is free to use what ever fallback image it wants - if it cares about Opera mini it can set fallback image to smaller one, if it cares more about proper size rendering of image then it can use bigger fallback image.
But i think we should document clearly somewhere why you should set smaller fallback image or why you should set bigger one, right?

catch’s picture

Also note that we did drop (nominal) support for one segment of Opera Mini recently, that had never been supported but was incorrectly specified: #3202818: Remove untrue declaration of Opera Mini (in reverse proxy mode) support from Drupal 9.3.

proweb.ua’s picture

#129 works

heddn’s picture

@pivica, if you want to do the honors of adding the wording for #137 and #138, I'll be happy to review/RTBC.

drupaldope’s picture

regarding this issue,
I have been working with the module https://www.drupal.org/project/css_aspect_ratio

applying CSS aspect ratio allows for image dimensions being handled by CSS so the images require no explicit height and width other than set by image styles.

using this method, I have been able to achieve a score of 0 CLS with no reflow.

heddn’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new33.26 KB
new905 bytes
new36.49 KB

Here's the updated wording:

ranjith_kumar_k_u’s picture

StatusFileSize
new36.44 KB
new747 bytes

Fixed CS error.

Status: Needs review » Needs work

The last submitted patch, 150: 3192234-150.patch, failed testing. View results

heddn’s picture

Status: Needs work » Needs review
fabianx’s picture

Before reviewing, just putting out here that a compromise can also be to serve the smallest fallback image AND then use some JS shim to load a larger image -- most old browsers do support JS and such the responsive support can be emulated client side.

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC - The patch and approach looks great to me.

zcht’s picture

StatusFileSize
new586.68 KB

I have a question here, thanks for the patch that has worked great so far. I had to roll the patch after the update from Drupal 9.2 to 9.3, I noticed that something is not working correctly with an image style. in my specific example, it concerns the image style for logos, which is very quickly noticeable, especially on a 4k screen.

for logos i have the following image styles: 1x 100x100px, 2x 200x200px. for this i created a responsive image style, which uses the first image style for 1x and the second one for 2x. on a 4k monitor under drupal 9.2.x the logo was output in high res, so with 2x, but the visual size remained the same as on a non 4k screen.

since the last patch (#150), the logo on a 4k monitor is now output with 200x200px, so visually the logo is enlarged and appears very blurry. which is understandable, since you actually generated a size dimension of 200x200px. i have tried everything possible but it has all brought nothing. so i have first simply taken out the version 2x, so that the visual output of the logos is correct, even if it is now of course very blurry output on 4k resolution.

attached a screenshot that illustrates the problem well.

heddn’s picture

@zcht, can you share the rendered HTML for 9.2 (#25) vs 9.3 (##150?

zcht’s picture

@heddn good idea, attached both versions. it seems that in patch #150 width & height is changed, is also already in patch #129 exactly the same. that's why this "effect" occurs.

Drupal 9.2.x + patch #25

<a href="https://mywebsite.host/abc">     
  
  <div class="media media--blazy media--bundle--newsroom media--loading is-b-loading media--switch media--switch--content media--responsive media--image">
  
  <noscript>

  <picture>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=SJ6VoMFH 2x" media="all and (min-width: 1600px)" type="image/webp" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/webp" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=s3QfTshE 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/webp" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 600px) and (max-width: 899px)" type="image/webp" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (max-width: 599px)" type="image/webp" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=SJ6VoMFH 2x" media="all and (min-width: 1600px)" type="image/png" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/png" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=s3QfTshE 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/png" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 600px) and (max-width: 899px)" type="image/png" width="100" height="100"/>
    <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (max-width: 599px)" type="image/png" width="100" height="100"/>

    <img class="media__image media__element" src="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac" width="100" height="100" loading="lazy" />
  </picture>

  </noscript>
    
  <picture>
    <source srcset="" media="all and (min-width: 1600px)" type="image/webp" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=SJ6VoMFH 2x"/>
    <source srcset="" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/webp" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/webp" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=s3QfTshE 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 600px) and (max-width: 899px)" type="image/webp" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (max-width: 599px)" type="image/webp" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 1600px)" type="image/png" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=SJ6VoMFH 2x"/>
    <source srcset="" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/png" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/png" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=s3QfTshE 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 600px) and (max-width: 899px)" type="image/png" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (max-width: 599px)" type="image/png" width="100" height="100" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>

    <img class="media__image media__element b-lazy b-responsive" data-src="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac" src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D&#039;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&#039;%20viewBox%3D&#039;0%200%201024%201024&#039;%2F%3E" width="100" height="100" alt="abc" loading="lazy" />

  </picture>
  </div>
  
</a>

-------

Drupal 9.3.x + patch #150

<a href="https://mywebsite.host/abc">

  <div class="media media--blazy media--bundle--newsroom is-b-loading media--switch media--switch--content media--responsive media--image">

  <picture>
    <source srcset="" media="all and (min-width: 1600px)" type="image/webp" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/webp" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/webp" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 600px) and (max-width: 899px)" type="image/webp" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (max-width: 599px)" type="image/webp" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 1600px)" type="image/png" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/png" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/png" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (min-width: 600px) and (max-width: 899px)" type="image/png" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>
    <source srcset="" media="all and (max-width: 599px)" type="image/png" width="200" height="200" data-srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x"/>

    <img loading="lazy" class="media__image media__element b-lazy b-responsive" decoding="async" data-src="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac" src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D&#039;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&#039;%20viewBox%3D&#039;0%200%201024%201024&#039;%2F%3E" width="100" height="100" alt="abc" />
  </picture>

  <noscript>
    <picture>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 1600px)" type="image/webp" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/webp" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/webp" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (min-width: 600px) and (max-width: 899px)" type="image/webp" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.webp?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.webp?itok=rdX6a7e5 2x" media="all and (max-width: 599px)" type="image/webp" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 1600px)" type="image/png" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 1024px) and (max-width: 1599px)" type="image/png" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 900px) and (max-width: 1023px)" type="image/png" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (min-width: 600px) and (max-width: 899px)" type="image/png" width="200" height="200"/>
      <source srcset="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac 1x, /sites/default/files/styles/myimagestylex2/public/logo/logo.png?itok=rdX6a7e5 2x" media="all and (max-width: 599px)" type="image/png" width="200" height="200"/>

      <img loading="lazy" class="media__image media__element" decoding="async" src="/sites/default/files/styles/myimagestyle/public/logo/logo.png?itok=uKDzrnac" width="100" height="100" />
    </picture>
  </noscript>        
  
  </div>
</a>
heddn’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new5.33 KB
new38.4 KB

While digging into #157, I think I also found a partial solution to #134. Or at least, we now have test coverage for both of those flagged items. Let's see how this fares.

drupaldope’s picture

let's hope it will not break working solutions using CSS aspect ratio

rar9’s picture

Drupal 9.3.5

Patch #158 in a VIEW block -> Lazy loading attribute EAGER is selected for resposive Media Images, but Images stays defined as LAZY.

(Block as bootstrap 4 carousel)

zcht’s picture

Patch #158 works fine for me, thanks for that. i can also confirm the observation of comment #160.

heddn’s picture

Status: Needs review » Needs work

NW for #160.

heddn’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new54.49 KB
new91.71 KB

I cannot reproduce #160/#161. Did you perhaps miss the loading options in views? See attached screenshots of views configuration:

Configured as Eager:

Rendered as Eager:

zcht’s picture

My mistake, @heddn is right in comment #163. everything works with the latest patch as requested and perfect with drupal 9.3.5, thanks again for that :)

RTBC++ for patch #158

heddn’s picture

Status: Needs review » Reviewed & tested by the community
glynster’s picture

Great work everyone. Lighthouse tests are much better and the option to switch in view modes from Eager to Lazy gives you all the flexibility you need. RTBC + 1

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 158: 3192234-158.patch, failed testing. View results

catch’s picture

  1. +++ b/core/modules/responsive_image/responsive_image.module
    @@ -365,7 +379,7 @@ function _responsive_image_build_source_attributes(array $variables, BreakpointI
       $derivative_mime_types = [];
    -  foreach ($multipliers as $multiplier => $image_style_mapping) {
    +  foreach (array_reverse($multipliers) as $multiplier => $image_style_mapping) {
         switch ($image_style_mapping['image_mapping_type']) {
    

    Could use a comment as to why we use array_reverse()

  2. +++ b/core/modules/responsive_image/responsive_image.post_update.php
    @@ -13,3 +13,24 @@ function responsive_image_removed_post_updates() {
    + */
    +function responsive_image_post_update_image_loading_attribute() {
    +  $storage = \Drupal::entityTypeManager()->getStorage('entity_view_display');
    +  foreach ($storage->loadMultiple() as $view_display) {
    +    $changed = FALSE;
    +    /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */
    +    foreach ($view_display->getComponents() as $field => $component) {
    +      if (isset($component['type']) && ($component['type'] === 'responsive_image')) {
    +        $component['settings']['image_loading']['attribute'] = 'lazy';
    +        $view_display->setComponent($field, $component);
    +        $changed = TRUE;
    +      }
    +    }
    +    if ($changed) {
    +      $view_display->save();
    +    }
    +  }
    

    The manipulation of the views should happen in presave of views config entities - lots of examples in views post updates and config listeners where similar things happen. The update can then just use ConfigEntityUpdater (which would also help with the lack of batch here).

  3. +++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
    @@ -148,6 +153,27 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    +      '#title' => $this->t('Image loading'),
    +      '#weight' => 10,
    +      '#description' => $this->t('Image assets are rendered with native browser loading attribute of (<em>loading="lazy"</em>) by default. This improves performance by allowing modern browsers to lazily load images without JavaScript. It is sometimes desirable to override this default to force browsers to download an image as soon as possible using the "<em>eager</em>" value instead.'),
    +    ];
    

    Would be nice if we could make this a bit more concise somehow.

    Maybe 'Modern browser will lazily load images with the 'loading="lazy"' attribut (default) without JavaScript. Choose 'eager' to force browsers to download an image so soon as possible.'?

rar9’s picture

With responsive images https://validator.w3.org is complaining about :

  • Error: Attribute width not allowed on element source at this point.
  • Error: Attribute height not allowed on element source at this point.
heddn’s picture

While working on the feedback from #168, I found another bug. If there are breakpoints like:

  • 1x
  • 1.5x
  • 2x

it sorts them:

  • 1.5x
  • 1x
  • 2x

This means that the docs in the code that all breakpoints are sorted in a certain way cannot be trusted. Working on a fix for that and other review points.

heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new41.78 KB
new6.54 KB

Responded to #168. Will also be opening up a new issue (hopefully a quickfix) that will block landing this patch for the problem IDed in #170.

Status: Needs review » Needs work

The last submitted patch, 171: 3192234-171.patch, failed testing. View results

heddn’s picture

Title: Apply width and height attributes to allow responsive image tag use loading="lazy" » [PP-1] Apply width and height attributes to allow responsive image tag use loading="lazy"
Status: Needs work » Needs review
StatusFileSize
new42.49 KB
new1.55 KB

Status: Needs review » Needs work

The last submitted patch, 173: 3192234-173.patch, failed testing. View results

heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new8.28 KB
new46.96 KB
yogeshmpawar’s picture

StatusFileSize
new46.96 KB
new478 bytes

Resolved CS errors & added an interdiff.

Status: Needs review » Needs work

The last submitted patch, 176: 3192234-176.patch, failed testing. View results

heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new3.43 KB
new46.96 KB
renrhaf’s picture

Tested #178, everything seems to be working as expected with a markup generated like this one :

<picture>
  <source srcset="URI DESKTOP 1x" media="all and (min-width: 768px)" type="image/webp" width="1920" height="500">
  <source srcset="URI TABLET 1x" media="(min-width: 444px)" type="image/webp" width="768" height="410">
  <source srcset="URI MOBILE 1x" media="(min-width: 0px)" type="image/webp" width="444" height="236">
  <img loading="lazy" src="URI" width="444" height="236">
</picture>

+1 RTBC

anybody’s picture

Great work @heddn and all others! Confirming RTBC+1! :)

#3267870: Order image mappings by breakpoint ID and numeric multiplier was also marked RTBC by Fabianx! :) Happy about these further improvements!

catch’s picture

  1. +++ b/core/modules/breakpoint/src/BreakpointManager.php
    @@ -133,8 +133,9 @@ public function processDefinition(&$definition, $plugin_id) {
         }
    -    // Ensure that multipliers are sorted correctly.
    -    sort($definition['multipliers']);
    +    // Ensure that multipliers are sorted numerically so 1x, 1.5x and 2x
    +    // come out in that order instead of 1.5x, 1x, 2x.
    +    sort($definition['multipliers'], SORT_NUMERIC);
       }
     
    

    Was going to ask for this to be split into its own issue, then I saw #3267870: Order image mappings by breakpoint ID and numeric multiplier, so I've committed that one.

  2. +++ b/core/modules/responsive_image/responsive_image.module
    @@ -212,6 +216,18 @@ function template_preprocess_responsive_image(&$variables) {
    +    $dimensions = responsive_image_get_image_dimensions($responsive_image_style->getFallbackImageStyle(), ['width' => $variables['width'], 'height' => $variables['height']], $variables['uri']);
    +    // Unset current image attributes, so the new ones that are set will work.
    +    unset($variables['img_element']['#attributes']['width']);
    +    unset($variables['img_element']['#attributes']['height']);
    +    $variables['img_element']['#width'] = $dimensions['width'];
    +    $variables['img_element']['#height'] = $dimensions['height'];
    +  }
     }
    

    It would be useful to explain in the comment why we unset #attributes then set #width and #height instead of just overwriting the attributes.

anybody’s picture

@catch Re #181:

Great to see all that progress! :)

It would be useful to explain in the comment why we unset #attributes then set #width and #height instead of just overwriting the attributes.

Did you perhaps overlook that the last two lines do NOT have #attributes?
So I think from code side the comment line above should be enough, because it's two different keys?

Or do you mean why #width and #height have to be set on the img_element directly and not on its #attributes? That's due to the render element, I guess?

But I think you may not have seen the difference there?

Thanks :)

heddn’s picture

Title: [PP-1] Apply width and height attributes to allow responsive image tag use loading="lazy" » Apply width and height attributes to allow responsive image tag use loading="lazy"
StatusFileSize
new44.17 KB

Needed a re-roll after #3267870: Order image mappings by breakpoint ID and numeric multiplier landed. The re-roll was pretty straight forward, There are fewer hunks now as we had a duplicate DB fixture and ResponsiveImageConfigUpdater class that were both created in that issue. No interdiff.

glynster’s picture

@heddn this patch only applies if you add #3267870: Order image mappings by breakpoint ID and numeric multiplier patch first. Otherwise both apply cleanly. It probably should be noted that both patches need to be applied.

glynster’s picture

Actually the patches apply cleaning but then we have a class error:

PHP Fatal error: Cannot use Drupal\Core\Config\Entity\ConfigEntityUpdater as ConfigEntityUpdater because the name is already in use in /app/web/core/modules/responsive_image/responsive_image.post_update.php on line 12

Up until now we have only been using the patch from 3192234-178.patch which does not require the additional patch.

agoradesign’s picture

@glynster the patch #183 was written in between #3267870-20: Order image mappings by breakpoint ID and numeric multiplier has been committed and later that day reverted. I think you should fallback to #178, right @heddn?

glynster’s picture

Roger that @agoradesign!

catch’s picture

Status: Needs review » Needs work

Test bot doesn't like #183.

@Anybody:

Or do you mean why #width and #height have to be set on the img_element directly and not on its #attributes? That's due to the render element, I guess?

Yes I mean a quick explanation of the different data structures that necessitate moving things around.

heddn’s picture

Title: Apply width and height attributes to allow responsive image tag use loading="lazy" » [PP-1] Apply width and height attributes to allow responsive image tag use loading="lazy"
Status: Needs work » Postponed
heddn’s picture

StatusFileSize
new70.7 KB
new4.2 KB
heddn’s picture

StatusFileSize
new44.37 KB

Interdiff in #190 is fine. Ignore the patch. Use this one instead.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

xamount’s picture

Hello @heddn, thanks for the great work here! I have tried the patch at #191 and I did it on top of #3267870: Order image mappings by breakpoint ID and numeric multiplier.

#3267870: Order image mappings by breakpoint ID and numeric multiplier applied cleanly but #191 did not. I just get the error that the patch was skipped and not applied. However, the files in the patch were actually updated and I can see width and height in the images.

I am not sure what is causing this. Does anyone else get this issue?

I ended up using the patch at #178 and that works. I just need to remember to remove this patch once #3267870: Order image mappings by breakpoint ID and numeric multiplier is committed.

rar9’s picture

patch #178 no longer applies for D9.4.0

ambient.impact’s picture

@Rar9 #190 works for me on 9.4.0 as long as you apply it after #3267870-47: Order image mappings by breakpoint ID and numeric multiplier.

glynster’s picture

xamount’s picture

#194, #195 and #196 are all correct and I am in agreement. I tried it again and confirm it works on D9.4.

For my comment in #193, I was trying to apply the patch on Drupal 9.3 which is why it didn't work.

johnpitcairn’s picture

Version: 9.5.x-dev » 10.1.x-dev

#3267870: Order image mappings by breakpoint ID and numeric multiplier is now Drupal 10.1-only so this needs to be 10.1 as well.

Christopher Riley’s picture

I have applied the patch 191 via composer, applied the patch #3267870-47: Order image mappings by breakpoint ID and numeric multiplier and all seemed to be fine. Went into the interface and set a style to eager load, however even after flushing the caches numerous times I am still seeing it lazy load not eager as I specified.

Suggestions?

alina.basarabeanu’s picture

We are using patch #191 on drupal 9.4.2, PHP version 8.0.21 together with the issue https://www.drupal.org/project/drupal/issues/3267870 patch #47

It applies cleanly and solves the issue in our project.

This issue depends on the Order image mappings by breakpoint ID and numeric multiplier issue which was Reviewed & tested by the community.
Would be great to have them both merged.

hitchshock’s picture

+1 RTBC
It works well on my projects.
I'm using the patch from #191 + #47 from https://www.drupal.org/project/drupal/issues/3267870

heddn’s picture

Title: [PP-1] Apply width and height attributes to allow responsive image tag use loading="lazy" » Apply width and height attributes to allow responsive image tag use loading="lazy"
Status: Postponed » Needs review

This is not un postponed. Probably needs a re-roll, but let's see.

smustgrave’s picture

Don't believe ViewsConfigUpdater is the D10 way to go?

smustgrave’s picture

StatusFileSize
new4.68 KB
new44.68 KB

But here's a reroll for 10.1.x

Unfortunately I got an error generating the interdiff

But the only conflicts really came out of ViewsConfigUpdaterTest where most of the code was actually removed for 10.x.

I added the modules back to the test and instead of doing a setup just added the code to the test funciton this patch is adding.

Status: Needs review » Needs work

The last submitted patch, 204: 3192234-204.patch, failed testing. View results

heddn’s picture

The DB fixture needs to change to drupal-9.4.0.filled.standard.php.gz instead of 9.0.

smustgrave’s picture

Status: Needs work » Needs review
StatusFileSize
new842 bytes
new44.68 KB
heddn’s picture

Status: Needs review » Needs work
+++ b/core/modules/responsive_image/responsive_image.module
@@ -508,3 +543,12 @@ function responsive_image_library_info_alter(array &$libraries, $module) {
+  $config_updater->processResponsiveImageField($view_display);

We need to add test coverage and do the BC dance. Similar to how it was handled in the order multiplier update. See https://git.drupalcode.org/project/drupal/-/commit/4c87cc0#e239d64cc3dfd...

smustgrave’s picture

Not sure I follow unfortunately.

If we need to do something similar to

   $deprecations_triggered = &$this->triggeredDeprecations['3267870'][$responsive_image_style->id()];
    if ($this->deprecationsEnabled && $changed && !$deprecations_triggered) {
      $deprecations_triggered = TRUE;
      @trigger_error(sprintf('The responsive image style multiplier re-ordering update for "%s" is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Profile, module and theme provided Responsive Image configuration should be updated to accommodate the changes described at https://www.drupal.org/node/3274803.', $responsive_image_style->id()), E_USER_DEPRECATED);
    }

Then is processResponsiveImageField being deprecated?

glynster’s picture

Sidenote: wanted to know if it is worth adding in the fetchpriority tag to help with LCP? Much like the load eager/lazy? There are examples here: https://web.dev/optimize-lcp/

<img fetchpriority="high" src="/path/to/hero-image.webp">
smustgrave’s picture

Personally think that could be it’s own issue vs expanding the scope of this ticket

glynster’s picture

@smustgrave makes sense. The progress of this issue has been huge!

luke.leber’s picture

Re #210: to help with LCP check out https://www.drupal.org/project/responsive_image_preload for a different approach.

Fetchpriority only reorders image assets. Preload reshuffles all requests.

glynster’s picture

@Luke.Leber thanks for the clarification and links!

heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new46.33 KB
new3.75 KB

This adds the BC layer I was attempting to say is needed. We need it for all the install profiles that wouldn't get fixed by only the post update. And for sites that play fast and loose with running db updates in general.

And yes, anything we can offload to a follow-up issue is better at this point. This issue is getting long at the tooth and its better to keep it very focused. However, adding more features/options should all be relatively easy since we'll have this issue for copy/pasting much of the test coverage and changes into.

glynster’s picture

Sounds awesome @heddn. The latest patch for Drupal 9.4.5 applies cleanly. The latest patch is for Drupal 10 only correct?

pooja saraah’s picture

StatusFileSize
new46.33 KB
new405 bytes

Fixed failed commands on #215
Attached patch against Drupal 10.1.x

heddn’s picture

Status: Needs review » Reviewed & tested by the community

The last patch just added additional test coverage. Let's try RTBC again.

anybody’s picture

Confirming RTBC and looking very much forward to this performance highlight :)
Thank you all so much!

timohuisman’s picture

StatusFileSize
new44.36 KB
new4.85 KB

Rerolled #191 against 9.4.x. Keep in mind that you still need #47 from 3267870.

glynster’s picture

@timohuisman applies cleanly for Drupal 9.4.6. RTBC + 1. As @Anybody excited to see this moved into core!

drupaldope’s picture

@glynster I am holding my breath to see if this breaks the CSS aspect ratio padding method for responsive images: https://www.drupal.org/project/css_aspect_ratio

catch’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/core/modules/views/src/ViewsConfigUpdater.php
@@ -110,6 +110,50 @@ public function setDeprecationsEnabled($enabled) {
 
+  /**
+   * Add lazy load options to all responsive_image type field configurations.
+   *
+   * @param \Drupal\views\ViewEntityInterface $view
+   *   The View to update.
+   *
+   * @return bool
+   *   Whether the view was updated.
+   */
+  public function needsResponsiveImageLazyLoadFieldUpdate(ViewEntityInterface $view): bool {
+    return $this->processDisplayHandlers($view, TRUE, function (&$handler, $handler_type) use ($view) {
+      return $this->processResponsiveImageLazyLoadFieldHandler($handler, $handler_type, $view);
+    });
+  }
+

There doesn't seem to be a post update in views to do this at all.

+++ b/core/modules/responsive_image/responsive_image.module
@@ -418,6 +438,21 @@ function _responsive_image_build_source_attributes(array $variables, BreakpointI
   }
+  // The images used in a particular srcset attribute should all have the same
+  // aspect ratio. The sizes attribute paired with the srcset attribute provides
+  // information on how much space these images take up within the viewport at
+  // different breakpoints, but the aspect ratios should remain the same across
+  // those breakpoints. Multiple source elements can be used for art direction,
+  // where aspect ratios should change at particular breakpoints. Each source
+  // element can still have srcset and sizes attributes to handle variations for
+  // that particular aspect ratio. Because the same aspect ratio is assumed for
+  // all images in a srcset, dimensions are always added to the source

Is this actually enforced anywhere in responsive image module?

longwave’s picture

Status: Needs review » Needs work

NW for #223, needsResponsiveImageLazyLoadFieldUpdate is only called from a test.

As well as a post update hook, I think we need to revert part of #3290810: Remove updates added prior to 9.4.0 (9.4.4 for ckeditor) and add 9.4.0 database dumps and reinstate views_view_presave() and ViewsConfigUpdater::updateAll(), which should then call the updater method. This handles views that are not present in the database when the update is run, but that might be added later by a config install.

heddn’s picture

Assigned: Unassigned » heddn

Is this actually enforced anywhere in responsive image module?

No, and I don't think we want to enforce this. What is mentioned here is best practices.

Working on fixing the post update. I think I'll just add the bits we need from #3290810: Remove updates added prior to 9.4.0 (9.4.4 for ckeditor) and add 9.4.0 database dumps to here.

heddn’s picture

Status: Needs work » Needs review
StatusFileSize
new48.92 KB
new3.04 KB

Responded to 223 and 224.

heddn’s picture

StatusFileSize
new48.92 KB
new774 bytes
berdir’s picture

StatusFileSize
new46.12 KB

Reroll of #220 for 9.5.x. https://www.drupal.org/project/drupal/issues/3267870#comment-14531100 is still needed (comment #47)

graber’s picture

Status: Needs review » Reviewed & tested by the community

RTBC +1

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

Added a question to the code review in gitlab...

graber’s picture

Replied. However, I have just one concern that just occurred to me: when the width and height attributes are added to images, it changes the appearance of the pages in some cases. Before the update smaller images were stretched to the width of the container, maintaining aspect ratio. Now they don't so they take less space than before. This'll change the appearance of sites that have images with smaller size than the actual space they fit in, there may be complains from some users as their layouts may break (css default width: auto to specified width: X). I can't think of any way to handle this and go forward though. But since we already have that implemented for standard images in https://www.drupal.org/project/drupal/issues/3167034..

heddn’s picture

re #232, there shouldn't be any BC concerns here. All upgraded sites should be set to eager still as that was the prior behavior. It is only sites that consciously change to lazy (and hopefully test) that this should impact.

graber’s picture

Setting loading to "eager" doesn't remove the width and height attributes. My test nodes just looks differently before and after applying the patch regardless of the loading setting on the image formatter. I say we should set width and height only if loading is set to "lazy" so we don't have any BC issues.

heddn’s picture

Status: Needs review » Needs work

Alex's views update concern is now addressed and test coverage added. Working on Marcin's feedback in #232, so setting back to NW for now.

graber’s picture

Status: Needs work » Reviewed & tested by the community

Ok, so I noticed we already broke that BC in #3167034: Leverage the 'loading' html attribute to enable lazy-load by default for images in Drupal core for the standard image formatter (applying width and height to all images) so doing it now for the responsive image formatter shouldn't be a big problem, a mention in release notes should be ok.

back to RTBC since all is addressed.

heddn’s picture

Issue summary: View changes
StatusFileSize
new93.93 KB
new65.32 KB

As a help to see the impact of what Marcin found, I uploaded the same image of a calendar (original was 100x122px). Umami default image styles resize larger this image and make it unreadable. But it seems to take up the container space it can get when no image dimensions are added (no patch). Once image dimensions are added, then the browser preserves the aspect ratio and shrinks the size.

With patch:

No patch:

My concern with addressing this deficiency is that if we only add dimensions to lazy, then eager doesn't benefit from this useful data. If we add an additional toggle on the field formatter to add/remove dimensions, that seems really strange. What we see here is something that seems like an existing bug that we resolve as a by-product of this issue. As a result, I'm also +1 on moving to RTBC.

heddn’s picture

Issue summary: View changes
StatusFileSize
new103.02 KB
alexpott’s picture

Status: Reviewed & tested by the community » Needs work

We need to fix the coding standards issues in the patch. I've also added some review comments to the MR.

anybody’s picture

Re #237

My concern with addressing this deficiency is that if we only add dimensions to lazy, then eager doesn't benefit from this useful data. If we add an additional toggle on the field formatter to add/remove dimensions, that seems really strange. What we see here is something that seems like an existing bug that we resolve as a by-product of this issue.

Totally agree in both points. Width and height on images are best-practice and also suggested by tool like Google Lighhouse. If anyone REALLY needs to remove them, there are hooks, but this is nothing that should be added to the UI and sites using that quirks shouldn't be a reason for blocking improvements. RTBC++ for these points.

Still NW as of #239

duaelfr’s picture

StatusFileSize
new26.09 KB

Rerolled MR on 9.5.x and removed test related stuff for people that would need that on their projects.
(Applies on 9.4.8 too)

heddn’s picture

Status: Needs work » Needs review
graber’s picture

Status: Needs review » Reviewed & tested by the community

I see all feedback addressed, back to RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

@heddn thanks for addressing all the feedback. I've got one more question about the array_reverse() - see the MR code review...

graber’s picture

Status: Needs review » Reviewed & tested by the community

I see the question was answered almost a week ago. Let's not prolong this too much as we don't want to spend too much time rebasing and the thread is long enough. Back to RTBC. If further questions arise, I propose merging this and creating follow-ups, let's remember this is a dev branch.

heddn’s picture

Status: Reviewed & tested by the community » Needs review

I think that https://codepen.io/heddn/pen/LYmKway means we have a problem. Or at least, we have a problem in FF. But it seems like if we remove dimensions on the fallback image in FF, then the problem goes away. Can someone else confirm my thinking?

heddn’s picture

Given the notes in https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture#try_it, I think we can safely _not_ add dimensions on the fallback img tag.

The <img> element serves two purposes:

It describes the size and other attributes of the image and its presentation.
It provides a fallback in case none of the offered elements are able to provide a usable image.

All modern browsers support picture element (that's how Drupal renders responsive images). All modern browsers support listing multiple file types and sizes as <source srcset=""/>. The fallback img element isn't really needed per se. We can and do still add it, but we don't need it for describing the size. The source element can do that for us. I hunted to see if/when support was made available for height/width on source elements and couldn't find it. It just seems to be assumed it always works. In my testing on FF and Chrome, that proves to be true. I'll roll these findings into an update of the MR. Meaning, we'll remove the dimensions on the fallback img in the picture element.

heddn’s picture

There was already good test coverage, so we just need to change it to test the new expecations. Yeah.

anybody’s picture

Status: Needs review » Needs work

Huge thanks @heddn! Tests failed:

  Line   core/modules/responsive_image/responsive_image.module  
 ------ ------------------------------------------------------- 
  204    Cannot unset offset 'height' on array{}.               
  204    Cannot unset offset 'width' on array{}.                
 ------ ------------------------------------------------------- 


 [ERROR] Found 2 errors        
heddn’s picture

Status: Needs work » Needs review

_sigh_

graber’s picture

Status: Needs review » Needs work
StatusFileSize
new1.33 MB

I hate that last commit but I guess we have no choice.
Following the last lead, tested this on demo_umami on Chrome and Firefox by changing breakpoint group of the 2:3 Image responsive image style to Umami and enabling the first 4 breakpoints with a single style in each (config below). The image looks different on Chrome and FF:

ff-chrome comparison 1

langcode: en
status: true
dependencies:
  config:
    - image.style.large
    - image.style.large_21_9
    - image.style.large_3_2_768x512
    - image.style.medium
    - image.style.square_small
  theme:
    - umami
_core:
  default_config_hash: mtmXtN8C-WzPGe-FLVGv1SrYZn1g5va-X8LeQt3iGoE
id: 3_2_image
label: '3:2 Image'
image_style_mappings:
  -
    image_mapping_type: image_style
    image_mapping: large_21_9
    breakpoint_id: umami.wide
    multiplier: 1x
  -
    image_mapping_type: image_style
    image_mapping: large_3_2_768x512
    breakpoint_id: umami.wide
    multiplier: 2x
  -
    image_mapping_type: image_style
    image_mapping: large
    breakpoint_id: umami.narrow
    multiplier: 1x
  -
    image_mapping_type: image_style
    image_mapping: medium
    breakpoint_id: umami.narrow
    multiplier: 2x
breakpoint_group: umami
fallback_image_style: square_small

To reproduce:

  1. `drush si demo_umami`,
  2. `drush cex -y`,
  3. update /config/sync/responsive_image.styles.3_2_image.yml with the given config (leave uuid),
  4. `drush cim -y`,
  5. visit /en/articles/dairy-free-and-delicious-milk-chocolate on FF and Chrome.
graber’s picture

If I zoom out to 50% on both browsers, FF displays a different style (the 21x9 one), while Chrome stays on the large one even at 25%. I think it'd be good if someone with more frontend experience checked this out.

martijn de wit’s picture

@Graber why is the multiplier set at "2x" for this test? If the multiplier is set on 1x at every breakpoint, will the test go well?

graber’s picture

Status: Needs work » Reviewed & tested by the community

As to why - random test values, no specific reason. With multiplier set to 1x everything renders identically on Chrome and FF.
I guess this issue doesn't have anything to do with the multiplier so setting this to RTBC.

Do wed an issue for the multiplier inconsistency?

Thanks for the hint @Martijn!

catch’s picture

Let's definitely open an issue for the multiplier inconsistency. I did find #2572325: Responsive image styles can be configured so that the picture tag output does not follow the specs which affects multiplier behaviour although doesn't look particularly likely to cause this issue, worth linking the two though.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Added a couple of small review comments to the MR>

heddn’s picture

Status: Needs work » Reviewed & tested by the community

Minor review comments addressed. Back to RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs release note, +Needs change record updates

Been through the issue and read a lot of the comments to sort out issue credit. Two questions emerge from doing that:

  • Do we know the answer to @manarak's question about their contrib module css_aspect_ratio in #222
  • Are we concerned about html validator issues - as @Rar9 pointed out in #169

Setting back to needs review to get answers to these questions.

We also need a release note to describe the changes this issue brings plus I'm not sure that the current change record really does the issue justice. Like it doesn't mention anything about aspect ratios, browser reflow and adding dimensions.

I've credited everyone who has made constructive discussion, code review and submitted patches which have moved the issue forward. Hopefully I've done this fairly - issues with lots of contributors & comments like this one make this quite a tricky task.

heddn’s picture

I think we need the markup that was failing validation in #169 to completely answer that question. But the markup listed in the CR https://www.drupal.org/node/3279032 doesn't fail validation.

As far as #222, I installed that contrib module in a vanilla demo_umami, applied #3286834: Automated Drupal 10 compatibility fixes and configured it for the following responsive images view modes:

  • Responsive 3x2 (hero image on recipies)
  • Scale crop 7:3 large (banner image on homepage)

I didn't see any visible difference in rendering of the image. I tested in FF withe cache clears, just in case CSS aggregation was caching things.

heddn’s picture

Updated CR and added a release notes snippet.

andypost’s picture

Status: Needs review » Reviewed & tested by the community

There should not be a difference, just new attribute

Back to RTBC

drupaldope’s picture

#259
I'm not familiar with Umami image sizes and aspect ratios, but the CSS Aspect Ratio module's strength lies in handling aspect ratios of images that are rendered in variable size, for example a % of height or width and then have an aspect ratio applied.

For example, render a 16:9 image of which we know only the variable width (for example 80vw, depending on device width or manual browser width) and the aspect ratio.

did you check if it also worked with variable width image containers, displaying the correct image ratio and correct image sizes ?

for example if you put a 3:1 hero into a 80vw container, and then drag the browser window narrow/wide
or if you use a 2:3 photo in a 33vw column
is the css aspect ratio maintained ?

heddn’s picture

re #262: those seem like good questions. Throw examples of this into codepen or some place and see what happens. The markup in the linked CR should give you an idea of the 2 styles of tags used to support responsive image and what images will look like moving forward. That said, I think much of the ask here is more about how do browsers support the addition of dimensions of media. I did some manual testing in that space back in #246 and Marcin did in #251. And as a result of that testing, we made some recent modifications. I _think_ we are good, but more manual testing is never bad.

wim leers’s picture

Status: Reviewed & tested by the community » Needs work
heddn’s picture

Status: Needs work » Needs review
klemendev’s picture

This is quite an important issue as it can severely impact CLS. What patch can be used and tested on Drupal 9.4.8?

martijn de wit’s picture

@KlemenDEV This won't be coming to D9 as far I see it.
This ticket depends on #3267870: Order image mappings by breakpoint ID and numeric multiplier and that is only fixed in D10.1

Good news D10 will be released soon :)

luke.leber’s picture

I agree with #266. This issue has become largely incomprehensible for "real world" applications. Most of us won't be upgrading to 10.x for at least N months after it's released while all but the "top 500" contributed module ecosystem scrambles to catch up.

@KlemenDEV - Here's what we're using for Drupal 9.4.x:

"patches": {
  "drupal/core": {
    "Order image mappings by breakpoint ID and numeric multiplier": "https://www.drupal.org/files/issues/2022-05-19/3267870-9.5.x-47.patch",
    "Apply width and height attributes to responsive image tag": "https://www.drupal.org/files/issues/2022-09-21/3192234-220-9.4.x.patch"
  },
}

This took a lot more effort to figure out than it probably should have.

Note - the order of patches matters!

glynster’s picture

Same goes for us using Drupal 9.4.x @KlemenDEV as @Luke.Leber composer patch explains.

klemendev’s picture

Thanks for the patch. Indeed it is a bit unrealistic that people will update to D10 that fast as many modules are not ready yet.

graber’s picture

Status: Needs review » Reviewed & tested by the community

I really hate the need to run the config update on every view save but unfortunately there's no other way to handle old config from newly installed modules currently as discussed with Lucas. RTBC again.

klemendev’s picture

Patch looks RTBC to me too. Using on D9. Hope this gets back-ported to 9.4.x or at least 9.5.x as some of us will not be able to move to D10 just yet due to contrib modules

berdir’s picture

Issue summary: View changes

It will not, that's guaranteed at this point. This will only be in 10.*1*, which means it's 6/7 months out from landing in a release anyway. #268 has the patches, we have been using some combination of patches since we created this issue almost 2 years ago. I put the patch info (thanks for sharing that, would have need to look it the current ones in our project) at the top of the issue summary, so we don't keep bugging 100+ people about this ;)

  • catch committed f8eb47e on 10.1.x
    Issue #3192234 by heddn, pivica, Qusai Taha, yogeshmpawar, bingolitte,...
catch’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed
Issue tags: +10.1.0 release highlights, +10.1.0 release notes

OK I think this is in a good state, and it's the sort of issue I'd prefer to get in earlier during a minor release cycle than later.

It would be good if someone could explicitly test this patch with https://www.drupal.org/project/css_aspect_ratio, but given that module has 6 sites reporting back and no stable release, I don't think we should hold this issue up on that testing. If something does break, it should be straightforward enough for css_aspect_ratio to override the behaviour here and get things going again.

Per @Berdir this issue won't and cannot be backported to 10.0.x and 9.5.x, let alone 9.4.x - it includes an upgrade path which we try to avoid adding to patch releases or release candidates at all cost. Sites can apply the patch if they need to. Lots of comments on issues about whether or not they're going to get backported can disrupt the process of getting them committed at all, sometimes pushing things out months or years because it's impossible to follow what's actually going on with the patch itself.

Did my best with issue credit but with 270+ comments it's bound to be imperfect.

This is an important front end performance improvement, so tagging for release highlights. Also slightly expanded the release notes snippet and tagging for that.

davedg629’s picture

Heads up for anyone using Media Responsive Thumbnail, you'll need to apply this patch or your images won't respect eager loading settings.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

quietone’s picture

I published the CR.

glynster’s picture

Proposed patch for Drupal 9 no longer applies for Drupal 9.5
https://www.drupal.org/files/issues/2022-09-21/3192234-220-9.4.x.patch

berdir’s picture

Issue summary: View changes

I updated the issue summary with the correct patch for 9.5.

glynster’s picture

@Berdir thanks so much, patches perfectly now!

marcoka’s picture

https://www.drupal.org/files/issues/2022-09-30/3192234-228-9.5.x.patch does not apply perfectly here.
Drupal 9.5

patching file core/modules/responsive_image/config/schema/responsive_image.schema.yml
patching file core/modules/responsive_image/responsive_image.module
patching file core/modules/responsive_image/responsive_image.post_update.php
Hunk #1 FAILED at 6.
Hunk #2 succeeded at 13 with fuzz 2 (offset -16 lines).
1 out of 2 hunks FAILED -- saving rejects to file core/modules/responsive_image/responsive_image.post_update.php.rej
patching file core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php
can't find file to patch at input line 253
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/core/modules/responsive_image/src/ResponsiveImageConfigUpdater.php b/core/modules/responsive_image/src/ResponsiveImageConfigUpdater.php
|index ff28e96aa68..880bb347df5 100644
|--- a/core/modules/responsive_image/src/ResponsiveImageConfigUpdater.php
|+++ b/core/modules/responsive_image/src/ResponsiveImageConfigUpdater.php
--------------------------
File to patch: 
glynster’s picture

@marcoka are you including both patches:

"patches": {
  "drupal/core": {
    "Order image mappings by breakpoint ID and numeric multiplier": "https://www.drupal.org/files/issues/2022-05-19/3267870-9.5.x-47.patch",
    "Apply width and height attributes to responsive image tag": "https://www.drupal.org/files/issues/2022-09-30/3192234-228-9.5.x.patch"
  },
}

I would also strongly suggest using the composer.json file to set all your patches. We are using the latest Drupal 9.5 and patches apply cleanly.

marcoka’s picture

Ah sorry, my bad. Will do. Thank you.
You apply them using cweagans/composer-patches i guess. Found this at aquias site.
https://support-acquia.force.com/s/article/360048081193-Managing-patches...
In the correct order everything works fine.

Also remember running DB updates!

klemendev’s picture

Patches also work for us on 9.5.0 so I suggest double checking patch order

julien@webstanz.be’s picture

Patches work for us (9.4.x)

Thx

catch’s picture

Issue summary: View changes
xjm’s picture

This snippet was already added to the 10.1.0 release notes draft.

d.fisher’s picture

duaelfr’s picture

Hi @darren.fisher!
The patch is meant for D9 so you won't be able to apply it on D10.
You can try to apply the patch extracted from the commit but it might not work either as it's been done for D10.1 and not D10.0

super_romeo’s picture

Still no patch for D10.0?

heddn’s picture

I think it is because it landed in 10.1.

berdir’s picture

Issue summary: View changes
StatusFileSize
new49.39 KB

The merge request diff kinda applies but fails on class not found errors because it assumes they are already there from other update functions.

Uploading a D10 patch and also adding patch instructions here and in the issue summary. I hope we can finally let this issue rest in piece with that :)

"patches": {
  "drupal/core": {
    "Order image mappings by breakpoint ID and numeric multiplier": "https://www.drupal.org/files/issues/2022-05-19/3267870-9.5.x-47.patch",
    "3192234: Apply width and height attributes to responsive image tag": "https://www.drupal.org/files/issues/2023-04-07/3192234-293-10.0.x.patch",
  },
}
klemendev’s picture

Big thanks for D10 patch @Berdir, I am confident multiple people were holding with D10 migration due to lack of this patch/feature on 10.0

anybody’s picture

#293 sadly doesn't seem to apply on 10.0.8 anymore.
Edit: Overread the dependency comment, sorry!

anybody’s picture

Google Pagespeed is complaning about missing width and height attributes on the fallback image now.

The commit contained these lines:

+    // We don't set dimensions for fallback image if rendered in picture tag.
+    // In Firefox, it results in sizing the entire picture element to the size
+    // of the fallback image, instead of the size on the source element.
+    $dimensions = responsive_image_get_image_dimensions($responsive_image_style->getFallbackImageStyle(), [
+      'width' => $variables['width'],
+      'height' => $variables['height'],
+    ],
+      $variables['uri']
+    );
+    $variables['img_element']['#width'] = $dimensions['width'];
+    $variables['img_element']['#height'] = $dimensions['height'];

In the issue summary and comment #15 I found

Firefox has open issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1694741 (linked from https://github.com/mozilla/standards-positions/issues/485)

when looking for "Firefox".
Both are closed. Might have been fixed between this issue and commen was created in 2021 and now.

Pagespeed says:

Image elements do not have explicit width and height
Set an explicit width and height on image elements to reduce layout shifts and improve CLS

for some <img loading="lazy" ... />'s within picture tags. This makes sense because if the image is lazy, it should also have width/height. And it should be the browsers job to handle the values correctly.

So should we add a follow-up to investigate on removing this exclusion?

agoradesign’s picture

good catch! this sounds like a really important change

heddn’s picture

Perhaps those are thoughts that could be carried over into #3213491: Add fallback format support to responsive images.

klemendev’s picture

In what cases does this happen, because, on 9.5.x, the fallback image gets the correct parameters (width and height are set) set when using the patched version?

anybody’s picture

Issue summary: View changes
StatusFileSize
new30.31 KB

@KlemenDEV: That sounds strange, as the code in #296 is from the patch in #293 and I also checked the commit into 10.1.x and it has this code present.

Could someone else please verify this and provide a screenshot?

@heddn re #298 after thinking about this for a while I think we shouldn't mix that.

Once #299 has been clarified, a separate issue should be added to discuss the removal.

anybody’s picture

klemendev’s picture

StatusFileSize
new83.17 KB
new45.04 KB

So to clarify #300 (we are running 9.5.x with "patch for Drupal 9" from the top of this issue), here are the settings:

Settings

and here is the code generated

Code

anybody’s picture

@KlemenDEV which patch exactly? Could you provide the composer patches lines? This still doesn't make a lot of sense to me from the code perspective.

klemendev’s picture

Here are the patches applied to the core:

"drupal/core": {
                "#3267870": "https://www.drupal.org/files/issues/2022-05-19/3267870-9.5.x-47.patch",
                "#3192234": "https://www.drupal.org/files/issues/2022-09-30/3192234-228-9.5.x.patch"
            },
anybody’s picture

@KlemenDEV thanks, you should update to the patches from #293 propably to have the same results as the commit for 10.1.x! This explains the differences - the older patch didn't have these lines which were merged into 10.1.x

anybody’s picture

So here's the follow-up: #3359421: (Re-)Add width / height also on fallback image to remove this extra-handling! :)

klemendev’s picture

Could someone a patch for 10.0.x from #293 that does not remove the width and height on the fallback image? I feel the amount of changes is too big for me to feel comfortable doing it

klemendev’s picture

StatusFileSize
new38.76 KB

Ok, I have tried to do it myself, so here is a patch for 10.0.x that sets the width and height of the fallback image too.

Scratch that, patch is not ok

klemendev’s picture

anybody’s picture

Assigned: heddn » Unassigned

Thank you @KlemenDEV but this issue is closed and that was already done in: #3359421: (Re-)Add width / height also on fallback image
but perhaps you'd like to review the MR over there?

klemendev’s picture

I can once I get 10.1 dev env setup for the websites I can test with.

I know this is closed, I just wanted to provide a patch for people that are using 10.0.x with patch and want to have width/height set too.

berdir’s picture

Sorry for the ping everyone, but we opened a follow-up issue where I'd love to get feedback on.

In short, somewhere between the D9 and D10 patches there was a change on how the width/height works and at least for us, that is causing issues for the design. We have a fairly simple patch that changes this and it mostly works for us but any kind of feedback would be useful whether that's correct or if there's another way: #3377420: Responsive image width/height values are not used from fallback image style.

heddn’s picture

xjm credited attiks.

xjm credited Bowevil.

xjm credited chananiel.

xjm credited ekl1773.

xjm credited Eric Heydrich.

xjm credited Jelle_S.

xjm credited jofitz.

xjm credited pixelite.

xjm credited RainbowArray.

xjm’s picture

Adding a bunch of missed credits from a duplicate of this issue circa 2015-2017 (plus triage credits for @quietone and @andypost).