Problem/Motivation

In #3192234: Apply width and height attributes to allow responsive image tag use loading="lazy" we improved responsive image support and added width and height attributes to image to prevent layout shift for lazy loaded images.

In the same issue the code is added that calculates width and height dimensions. First we will get the width and height from the smallest responsive image style and we put width and height in $variables['attributes']

    foreach ($variables['sources'][0] as $attribute => $value) {
      if ($attribute != 'type') {
        $variables['attributes'][$attribute] = $value;
      }
    }

and then in next code we are getting width and height from fallback image style which are put in $variables['img_element']

  if (isset($variables['sources']) && count($variables['sources']) === 1 && !isset($variables['sources'][0]['media'])) {
    ...
    // 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'];
  }

The problem is on the end of this function where $variables['attributes'] and $variables['img_element'] values are merged:

  if (isset($variables['attributes'])) {
    ...
    $variables['img_element']['#attributes'] = $variables['attributes'];
  }

This will overwrite fallback image style width and height with width and height which are calculated from smallest image style. Because of this images will be rendered with the smallest image dimension in browser. This is not ideal and we can not fix this with CSS. We need more accurate width and height values set here that are coming from fallback image style.

Proposed resolution

Make sure that width and height from fallback image style is used and not the width and height from smallest image style.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Release notes snippet

TODO.

Issue fork drupal-3377420

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

Issue summary: View changes
pivica’s picture

Status: Active » Needs review
StatusFileSize
new866 bytes

Here is a patch.

Status: Needs review » Needs work
pivica’s picture

Status: Needs work » Needs review
StatusFileSize
new1.5 KB
new2.35 KB

Test fix.

Status: Needs review » Needs work
pivica’s picture

Status: Needs work » Needs review
StatusFileSize
new1.7 KB
new3.64 KB

More test fixing.

Status: Needs review » Needs work
pivica’s picture

Status: Needs work » Needs review
StatusFileSize
new1.7 KB
new3.64 KB

One more try for test fix.

pivica’s picture

Issue summary: View changes
StatusFileSize
new672.68 KB
new730.35 KB

Tested this quite a bit and all reported problems in issue description are fixed.

If you upload small image and image styles are configured in that way that bigger styles can not produce big images then width and height will be calculated only against valid styles. This works as expected.

However, I did found one edge case when new behavior is not correct. The setup is like this:
1. We have 2 image styles 'Medium (220x220)' and 'Large (480x480)'
2. We have responsive image style with next setup
- 1x Mobile []: Use single image style 'Medium'
- 1.5x Mobile []: Use single image style 'Large'
- 2x Mobile []: Use single image style 'Large'
- Fallback image style is set to 'Large'

On the page we upload two images, one with the size of 480px width, and second with dimensions of 900px width.

When testing for a device with 250px width and DPR: 1 the first smaller image will be a bit bigger because width of image is calculated to 480px (from fallback 'Large' style) but browser will use 'Medium' style. This looks like this:

As you can see image is slightly scaled (250px) instead of original 220px.

Ideally for this case, we should use width of 220 and show image like this:

This is not that big of a deal, I guess for some special cases image could be stretched more, so you could start to see visual degradation because of scaling.

Not sure how to proceed because of this. IMHO I think that a new behavior (using correct values from fallback image) is better than the current one, but there are still some problems.

I am wondering should we remove width and height attribs and instead of them use inline aspect-ratio. The original reason we added width and height were to help browser to correctly calculate image dimensions for lazy loaded images, so we can avoid layout shifting when images are loaded. Feels a bit awkward to use inline style to solve this problem, but does it make actual sense?

sergey-serov’s picture

Greetings!
Is this correct standard behavior? (look at screenshot, please).
"Width" and "height" attributes freeze image at size of the "fallback image".
No any "css" modification here.
When width of the screen becomes bigger - in browsers web-developer tool is visible that now is used larger image with 570px. But on the page image is still small 190px.

sergey-serov’s picture

StatusFileSize
new123.77 KB
pivica’s picture

@sergey-serov yes, you exactly described the same problem we have and patch in this issue is fixing this. However there is one edge case explained in comment #10 which is a new problem when this patch is applied - it is smaller problem then current core behavior but still a problem and not fully correct behavior.

sergey-serov’s picture

@pivica Thank You, for explanation!
I spent several hours at last weekend with this thing :))

martijn de wit’s picture

pivica’s picture

Issue summary: View changes
smustgrave’s picture

Component: image system » responsive_image.module
Status: Needs review » Needs work
Issue tags: +Needs subsystem maintainer review

Updating for responsive images. Also tagging for the submaintainer thoughts.

But based on the fact this causes a regression not sure it go in until that gets resolved. With Drupal's BC policy that regression seems like it could negatively impact existing sites.

pivica’s picture

Update from @heddn from https://www.drupal.org/project/drupal/issues/3359421#comment-15186181 - we probably got this problem from that issue.

bkosborne’s picture

Seems like the issue summary may need an update since #3359421: (Re-)Add width / height also on fallback image was committed?

Beyond that, I'm confused why you'd want the width and height of an img src set to be the fallback image style? I have a responsive image style configured as such:

1x viewport sizing
type: select multiple image styles and use the sizes attribute
sizes: (min-width: 1440px) 1440px, 100vw
image styles: 8x3_2880w_1080h, 8x3_1440w_540h, 8x3_750w_281h
fallback image style: 8x3_1440w_540h

I don't have my fallback image style set to be the smallest image style. I chose the middle size as a compromise. If there's a browser that didn't support them, I don't want it to have a super grainy image, or assume that a super high res version is the best, so I chose the middle one.

pivica’s picture

> I don't have my fallback image style set to be the smallest image style. I chose the middle size as a compromise.

Maybe you use picture tag and it works fine for you? But in our case we use img tag with srcset and in this case it does not matter which fallback style you select, smallest or the biggest, currently you will always get width and height from the smallest style, which is not something you want as you said also.

bkosborne’s picture

StatusFileSize
new112.57 KB

Ultimately it's not a huge deal for us, as will use CSS to force the correct width of the image as needed.

But there's in incorrect statement in the issue summary:

This will overwrite fallback image style width and height with width and height which are calculated from smallest image style. Because of this images will be rendered with the smallest image dimension in browser.

It's not selecting the smallest. It's selecting the dimensions from the last image style in the set, which is not necessarily the smallest width. The list is sorted alphanumerically by machine name of the image style and processed in that order. You can observe this with the standard install profile in Drupal 10.1:

  1. Install 10.1 fresh using standard profile and enable Responsive Image
  2. Configure entity view display for Article and set the image field to use responsive image set to "Wide"
  3. Edit the "Wide" responsive image and observe it's set up with 1x viewport sizing, "Select multiple image styles and use the sizes attribute.", sizes set to "(min-width: 1290px) 1290px, 100vw" and Image styles selected Max 1300x1300, Max 2600x2600, Max 325x325, Max 650x650. Fallback set to Max 325x325. Don't change anything.
  4. Create an article and upload a very wide image (at least 2600 px wide)
  5. View the article and observe that the image is output as 650px width (the last image style listed).

Here's a screenshot to further demonstrate the issue:
The responsive image style settings form showing the order of image styles checkboxes

This patch overrides that to have ensure the fallback style is chosen as used for the dimensions instead.

I suppose that's fine, but I think this will need a change record, and the responsive image style form for the "Fallback Image Style" should probably be updated to indicate that whatever style is chosen as the fallback will be used for the image dimensions.

bspeare’s picture

Thank you for putting this together @pivica! After testing, this does seem like the correct fix for the expected functionality of the fallback image. As it is mentioned on https://web.dev/patterns/web-vitals-patterns/images/responsive-images, it is recommended to "set the width and height attributes to match the dimensions of the fallback image" and this patch fixes that problem.

thejimbirch’s picture

Hiding images in the files to make the patch easier to find.

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

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

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

berdir’s picture

Status: Needs work » Needs review

Rerolled and created a merge request.

smustgrave’s picture

Going to elevate to framework manager.

larowlan’s picture

Wondering what the contention is here? The MR looks straight forward - is the Needs FM review tag just because there's no Subsystem maintainer?

smustgrave’s picture

Issue tags: -Needs framework manager review

Got sign off in slack https://drupal.slack.com/archives/C04CHUX484T/p1717515262152809

Am doing a rebase as the MR is 500+ commits behind HEAD.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Ran test-only feature after rebase https://git.drupalcode.org/issue/drupal-3377420/-/jobs/1778003 and shows failure with test coverage

Tests all green!

  • nod_ committed a2d5bc50 on 10.4.x
    Issue #3377420 by pivica, Berdir, smustgrave, sergey-serov, bkosborne,...

  • nod_ committed a051706f on 11.0.x
    Issue #3377420 by pivica, Berdir, smustgrave, sergey-serov, bkosborne,...

  • nod_ committed 460a2ddd on 11.x
    Issue #3377420 by pivica, Berdir, smustgrave, sergey-serov, bkosborne,...

nod_’s picture

Version: 11.x-dev » 10.4.x-dev
Status: Reviewed & tested by the community » Fixed

Committed 460a2dd and pushed to 11.x. Thanks!

Status: Fixed » Closed (fixed)

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

jannakha’s picture

Just a note - fallback image style should be the largest image style in the set.
Wide responsive image has fallback image style "max 325x325" which sets <img ... width="325px">, even if the large image is loaded.

Setting an image `width="325px"` makes it render at this width, although it needs to be rendered at whatever the max width is required.

szato’s picture

@nod_, if I'm correct, it wasn't committed to 10.3.x.

Patch attached.

mariohernandez’s picture

Coming a little late to this discussion because I recently started experiencing issues when I use the img tag with srcset and sizes attributes. By default, the width and height attributes of the img tag is being updated to use the fallback image dimensions, which means my responsive images configuration is being totally ignored.
I am having the same issue as @sergey-serov (#11).
I typically use a medium or small image as my fallback image so if everything fails at least I get a decent image to render. However, this is breaking all my existing responsive images configuration because the width and height of the img tag is now the fallback image.
Everything seems to work if I use <picture>, but this is not always the recommended approach for responsive images. I use resolution switching as my default method.

Anyone else having this issue?

bkosborne’s picture

This is the problem I described in #19. I "fixed" this by using CSS to overwrite the size of the images.

fallenturtle’s picture

I'm having the same issue as https://www.drupal.org/project/drupal/issues/3377420#comment-15293179 using Drupal 10.5.3. Patch didn't work, so I guess I'll need to roll my own?
Edit: Patch didn't work because the changes in the patch are already made to 10.5.3.... so I have no idea what the problem is.