UPDATE:
For Drupal <= 11.2.10 use the patch in comment #17

For Drupal >= 11.3 use the patch in comment #37.
Starting with Drupal 11.3.0, the responsive image function in question has been replaced with methods on the class/service \Drupal\responsive_image\ResponsiveImageBuilder, and the original function was moved to a hook within the responsive_image module (ResponsiveImageThemeHooks.php). See issue 3548329.

Problem/Motivation

When configuring responsive image styles using the srcset and sizes attributes (Resolution switching), Drupal uses the fallback image’s width/height, rather than the dimensions of the image the browser selects, causing images to render with the wrong dimensions.

This does not seem to be an issue when using the <picture> element (Art direction).

Inside /core/modules/responsive_image/responsive_image.module the following snippet seems to cause the issue:

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

Wrongly rendered image

While inspecting the image above, dev tools show the correct image is loaded but the width and height attributes are altered to match the fallback image dimensions causing the image to not render as expected. The expected behavior is for that image to render full width, but because the fallback image is a smaller image, the issue above takes place.

Steps to reproduce

  1. Use Drupal 10.4+
  2. Create any image styles if necessary or use the existing image styles you may already have
  3. Configure a new Responsive Image Style using Responsive images from the Breakpoints group dropdown
  4. Choose "Select multiple image styles and use the sizes attribute." from the Type fieldset
  5. Select as many image styles as needed
  6. Type the desired sizes value in the Sizes field (i.e. (min-width:768px) 720px, 100vw))
  7. Select a fallback image (preferably an image that is not the size of how you expect your image to render)
  8. Create page where the new responsive image style is used and add images to it. Save it
  9. Your image should render using your fallback image dimensions

See attached screenshot.
Responsive images

Proposed resolution

Restore original responsive image rendering behavior which allowed images to be rendered at the size specified in the Sizes field.

Related issues:
https://www.drupal.org/project/drupal/issues/3377420 which seems to be where the new behavior stems from. Perhaps rethink the approach for ensuring the img tag dimensions reflect the correct image's dimensions, not the fallback image.

https://www.drupal.org/project/drupal/issues/3359421

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Issue fork drupal-3516726

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

mariohernandez created an issue. See original summary.

mariohernandez’s picture

Issue summary: View changes
mariohernandez’s picture

Issue summary: View changes
mariohernandez’s picture

StatusFileSize
new329.38 KB
new1.22 MB
new2.58 MB
new1.61 MB

I did additional research and testing using vanilla installations of Drupal 10.x.

First test - Using fallback image width and height

Expected behavior, image should render large on desktop (max 1290px), and full width on mobile.

1. First I configured responsive images (resp-img.png)
2. While inspecting the image, visually it looks tiny and that's because it is using the fallback image dimensions (dimensions.png)
3. However, looking at the Network tab in the dev tools, we see the right image is loaded, but because Drupal is changing the width and height of the img tag based on the fallback image dimensions (network.png)

Second test - Not using fallback image

1. Same responsive image configuration as above
2. Inspecting the image this time, reveals the right width/height on the image tag which is provided by the Sizes configuration in item #1 above.
3. The Network tab in inspector's console displays the right image dimensions and visually the image also looks correct (dimensions2.png)

Conclusion

Drupal is able to provide the right width and height to the img tag without resourcing to the fallback image. Hoping this can be resolved to be able to effectively use responsive images.

mariohernandez’s picture

Title: Image width/height from fallback breaks responsive images » Image width/height from fallback image breaks responsive images
mariohernandez’s picture

quietone’s picture

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

Changes are made on the main development branch 11.x first, then backported.

mariohernandez’s picture

Issue summary: View changes
agarzola’s picture

The question is how to determine which image to use for these values. Which image is most correct to use? From a progressive enhancement perspective, the fallback image seems like the correct choice, even though it creates the issue described here for images that are not sized with CSS.

mariohernandez’s picture

@agarzola, that a great question and that's the beauty of using srcset and sizes image attributes. The srcset lets you define a set of images each of which includes its width, allowing the browser to select the best image based on its width and the desired rendering size which is provided as part of the sizes attribute.

agarzola’s picture

Yes, that part is clear. What I am asking is what width and height attributes should be included in the img tag. Of all the inages included in the srcset, which one should Drupal use use to populate those attributes?

mariohernandez’s picture

@agarzola, I see what you mean. I think the width/height should be the one from the image selected by the browser. The browser analyzes the srcset and sizes attributes values then picks the best image that meets the rendering criteria, among other things. Up to this point, this has been the default behavior until I started seeing issues with fallback image width/height being applied to the img tag (thus this issue). By the way, this only seems to be an issue with srcset/sizes and not <picture>.

mariohernandez’s picture

Issue summary: View changes
mariohernandez’s picture

Issue summary: View changes
mariohernandez’s picture

Issue summary: View changes
StatusFileSize
new912.46 KB
mariohernandez’s picture

Issue summary: View changes
mariohernandez’s picture

Priority: Major » Normal
Status: Active » Needs review
StatusFileSize
new868 bytes

This patch removes the fallback image dimensions so they are not forced into the width/height attributes of the img tag.

agarzola’s picture

I think the width/height should be the one from the image selected by the browser.

I'm asking about the HTML attributes that are printed by Drupal in the HTML payload, not the rendered width and height in the browser. There needs to be some value in the width and height attributes. What values should Drupal use for those attributes if not the values from the fallback image?


This patch removes the fallback image dimensions so they are not forced into the width/height attributes of the img tag.

Removing the width and height attributes as proposed in #17 will cause content layout shift issues that were resolved in 3359421. Is that really what we want?

mariohernandez’s picture

Yes @agarzola, my answers remains the same. The width/height values for the HTML attributes should be those of the image selected by the browser. My argument is that what is the point of configuring responsive images with specific loading criteria, if they will be overriden by using fixed values from a fallback image?

As for issue 3359421, If thats where the breaking changes were introduce, then I would think they need to be implemented differently.

I appreciate your feedback and I hope with the help of the community we can come up with a solution that will work for everyone while adhering to the standards of responsive images.

smustgrave’s picture

Status: Needs review » Needs work

Patches should be in MR, and most likely will need a test case showing the issue.

mariohernandez’s picture

Hey there! I wanted to share some clarifications about this patch that might be helpful:

  1. Just a friendly reminder that the fallback image isn't meant to be your primary image solution. It's simply a safety net for browsers that don't support the srcset and sizes attributes (which is quite rare these days!). Since all major browsers have supported these features since 2017 (you can check out https://caniuse.com/?search=srcset for details), you probably won't need to rely on the fallback much at all.
  2. When you're using srcset and sizes, the browser automatically handles the image's width/height values. Each image in the srcset includes its width information, which helps the browser make smart decisions and apply the right dimensions to the image tag.
  3. When we force responsive images to use fallback image dimensions, we're actually undoing all the benefits of responsive design. The whole point is to let the browser choose the best image based on the user's device, screen resolution, and network conditions. By forcing a specific size, we're essentially going back to the pre-responsive era when we had to use one-size-fits-all images.
  4. If you're noticing layout issues, it might be worth revisiting your overall layout strategy. Ideally, your markup and CSS should work together to create flexible layouts for different breakpoints, with images naturally fitting their containers. A simple CSS rule like img { height: auto; max-width: 100%; } can ensure images never exceed their containers. Remember that your layouts should determine how images appear, while responsive images deliver the most appropriate file for each situation.

I hope this helps understand what's in play here.

damienmckenna’s picture

Could you please clarify what the HTML looks like before and after this change? I think that would help everyone understand what is happening. Thank you.

mariohernandez’s picture

StatusFileSize
new562.72 KB
new816.78 KB

@damienmckenna, certainly. The HTML does not look much different before/after the patch is applied. I've cleaned it up for better readability.

Before

<img loading="eager" 
  srcset="small.webp 360w, medium 480w, large.webp 768w" 
  sizes="(max-width:768px) 100vw, 720px" 
  width="480" 
  height="360" 
  src="medium.webp" alt="Image alt text">

After

<img loading="eager" 
  srcset="small.webp 360w, medium 480w, large.webp 768w" 
  sizes="(max-width:768px) 100vw, 720px" 
  width="768" 
  height="512" 
  src="medium.webp" alt="Image alt text">

The difference after the patch is applied is that the width and height of the img tag is set/forced to be that of the fallback image rather than using the dimensions of the image the browser has selected. As you can see, each image in the srcset has a width defined (i.e. 768w, this value is to instruct the browser how big this image is and in combination with the query in the sizes attribute, the browser is able to select the best image to meet the developer's intended rendering goal.
By using the fallback image dimensions as the img width/height, we are bypassing the concept of responsive images.

Here are before/after screenshots which show the issue when the fallback image is smaller than the size of the intended image. Some may say: "Why not use a larger fallback image?", true, but again, the whole goal of responsive images is for the browser to analyze the environment and select the best image for the job. In addition, what if I am dealing with an image that is, say, 2600px? this means my fallback image would need to be that large which I don't think is the best approach.

Before

Before

After

After

mariohernandez’s picture

damienmckenna’s picture

I wanted to know what the recommended solution was for the "width" and "height" attributes when using responsive images.

I couldn't find any recommendations on Mozilla's dev article on the topic or their <img> docs page.

I did find this article:

The article says "Set width and height to the resolution that corresponds to your default src." That suggests that Drupal core's handling of these attributes is correct and that we should close this as "won't fix".

damienmckenna’s picture

BTW it's not technically possible to set the image's width and height attributes to the specific image variation the browser will use as the HTML tag is generated at the server, and the server doesn't know what the browser is going to do with it.

mariohernandez’s picture

Yes, this is not an easy issue due to your last point of the server not knowing what the browser will do.
This may be a silly question, but based on the code examples in my previous comment, how were the width/height set? Was it Drupal doing that after the page was rendered?

I feel like responsive images works well when we let the browser do its job, but I do understand that in some cases there might be content shift when images don't contain a width/height. My concern with forcing a static width/height on the img is that this defeats the purpose of responsive images. So the question is, is there another way to capture width and height that is based on the image actually being selected by the browser rather than a random fallback image which purpose is simply to be used when browsers don't support responsive images?

mariohernandez’s picture

On smaller images, using a fixed image may work just fine and we wouldn't even need responsive images. This is the approach I take when images are intended to be rendered at a relatively small size across all breakpoints. However, when it comes to large images such as Hero images or full width images, this is when responsive images shine and using the fallback image approach would result in either upscaling images with CSS which is not recommended, or, using extremely large images as fallback which in turn will affect performance and maybe even UX.

damienmckenna’s picture

IMHO a major part of this is the CSS that goes with the image, so in the examples in #23 there might be CSS that also affect how the image is being displayed.

mariohernandez’s picture

I think there may be some level of CSS involved in process. Here are the most common ones:

  1. Using the following global rule: img { max-width: 100%; height: auto; }. This rule is pretty much best practice on most projects. It ensures the image never exceeds the width of the container it is in, and the image width will never be upscaled beyond its original image size.
  2. Other part where CSS plays a bigger part is in layouts. With the CSS rule above, the image will work in most cases as long as your layouts have been properly established using any of the available methods such as CSS Grid, Flexbox, plain'ol dimension settings on containers.
  3. Using CSS' aspect-ratio property can help the browser predict what the image approx size or aspect ratio will be.

It's not common practice to resize the actual <img> tag only using CSS. The recommended approach is to manage layouts around the image and images should naturally adapt to the layout containers.

The last point about using CSS for image dimensions, yes, it is true that you can actually resize images to the desired dimension with CSS, but just like images, CSS also need to be fully available during the page load process for those rules to kick in.

I feel like the issue is not so much the size of the image, the browser is already taking care of that for us, but just as important, is assigning the right width/height values to the img tag at load time (ideally the same dimensions the browser selected), to avoid affecting Largest Contentful Paint

josaku’s picture

#17 works for me (Drupal core 10.5.0). Thanks.
Moreover, I think that width and height in img could be replaced with one "sizes".
Is this way a resolution for two issues?
For example, in my case, the following code was generated after upgrading to 10.5.0 from 10.3.x.

<picture>
 <source srcset="XXX" media="all and (min-width: 992px)" type="image/png" sizes="240px"/>
 <source srcset="XXX" media="all and (min-width: 576px)" type="image/png" sizes="28vw"/>
 <source srcset="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x" media="all and (max-width: 575px)" type="image/gif"/>
 <img loading="eager" width="1" height="1" src="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="XXX" />
</picture>

However, this resolves the issue. (Of course, #17 is enough for me though)

<picture>
 <source srcset="XXX" media="all and (min-width: 992px)" type="image/png" sizes="240px"/>
 <source srcset="XXX" media="all and (min-width: 576px)" type="image/png" sizes="28vw"/>
 <source srcset="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x" media="all and (max-width: 575px)" type="image/gif"/>
 <img loading="eager" sizes="1" src="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="XXX" />
</picture>
luke.leber’s picture

I think that the root of this problem is that the original intent of #3377420 was to target the fallback image.

The <img> element is only a fallback when a <picture> tag is wrapped around it. Drupal's responsive image handling wraps a picture tag around markup conditionally. #3377420 also affects images that are not used in a fallback capacity.

Example configuration:

uuid: 70999a45-bb3c-41f7-9886-ba1fe271b26f
langcode: en
status: true
dependencies:
  config:
    - image.style.blog_featured_media_l
  theme:
    - wcstudent
id: blog_featured_media
label: 'Blog featured media'
image_style_mappings:
  -
    image_mapping_type: image_style
    image_mapping: blog_featured_media_l
    breakpoint_id: wcstudent.default
    multiplier: 1x
breakpoint_group: wcstudent
fallback_image_style: '_empty image_'

In this case, the responsive image style only has a single child image style -- which causes Drupal Core to omit the wrapping <picture> tag.

Example markup before #3377420

<img srcset="/sites/default/files/styles/blog_featured_media_l/public/2025-06/need-help-blog.png.webp?itok=HHMwicZj 1x" width="1200" height="900" src="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="a colorful note that reads &quot;need help?&quot; " loading="lazy">

After

<img srcset="/sites/default/files/styles/blog_featured_media_l/public/2025-06/need-help-blog.png.webp?itok=ikfUUuon 1x" width="1" height="1" src="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="a colorful note that reads &quot;need help?&quot; " loading="lazy">

The result is a pretty significant B/C break that makes the image inaccessible to sighted users.

mariohernandez’s picture

Version: 11.x-dev » 11.2.x-dev
Issue summary: View changes
Status: Needs work » Reviewed & tested by the community

Updated requirements for patch.

mariohernandez’s picture

Issue summary: View changes

Added issue reference about 11.3 change.

mariohernandez’s picture

Issue summary: View changes
StatusFileSize
new960 bytes

Added new patch for Drupal core 11.3 or higher.

For Drupal <= 11.2.10 use the patch in comment #17

For Drupal >= 11.3 use the patch in comment #37.

See 3548329 for details.

mariohernandez’s picture

Version: 11.2.x-dev » 11.x-dev
mariohernandez’s picture

Version: 11.x-dev » 11.3.x-dev
Issue summary: View changes
StatusFileSize
new960 bytes
mariohernandez’s picture

Issue summary: View changes
smustgrave’s picture

Version: 11.3.x-dev » 11.x-dev
Status: Reviewed & tested by the community » Needs work

Have not reviewed

But patches needs to be in an MR now
Also will need test coverage, if not already there.

mariohernandez’s picture

Added patch tests.

mariohernandez’s picture

Status: Needs work » Needs review

Created a MR from patch in comment #37. I'd appreciate your feedback: MR/14162

smustgrave’s picture

Status: Needs review » Needs work

MR appears to be missing test coverage. Tests should be included in the fix. But this change broke some existing tests which means this probably is a BC, so backwards compatibility will have to be considered

smustgrave’s picture

Patches don’t run the tests, DrupalCi was shut down a few years back but the MRs are much much faster

mariohernandez’s picture

Thanks for the feedback, @smustgrave. I'll add test to the MR.

mariohernandez changed the visibility of the branch main to hidden.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

mariohernandez’s picture

Status: Needs work » Needs review

Update the Functional tests with backwards compatibility.

smustgrave’s picture

Status: Needs review » Needs work

Sorry this one appears to need a rebase.

If you are another contributor eager to jump in, please allow the previous poster(s) at least 48 hours to respond to feedback first, so they have the opportunity to finish what they started!