By Martijn Steenbergen

The srcset cant help you

This post started out as a me screaming at img elements, but ended up as a overview of the state of the art of image handling on the web

Images on the web are a wonderful thing. At this point everyone knows how to plop in an image into a page. However, I ran into a fun problem. Let’s say your CDN has three different image sizes:

/965x1200.jpg, 
/550x683.jpg, 
/250x200.jpg

I wanted to create a generic image component that would automatically determine its own size and download the correct image, upscaling where necessary.

Turns out this is impossible.

srcset looks great

The first thing you do when starting with this is doing research. As usual, mdn is a great resource for web stuff and css tricks hits it out of the park. On a normal img element, you just set a src. Srcset allows you to describe multiple sources for your image element. You can do this by writing a comma separated list of images, comprised of the url of the image and the width in pixels. The fact you don’t write px as pixels, but w we’ll just take as the weirdness of the web. This could lead to the following element

<img width="400" height="400" src="/images/fallback-image.png" srcset="/965x1200.jpg 965w, /550x683.jpg 550w, /250x200.jpg 200w" alt="Apple Watch">

In a perfect world, this would be enough. However, in practice and for practical reasons this does not work.

How the browser downloads an image

The browser is smart and highly optimised (of course). So once it gets the html from the server, it doesn’t want to wait until all the css is loaded, it calculated how the page is going to look like and in turn how wide your image is, before it decides which image it loads. This problem is not just hypothetical, Mozilla found a 19% improvement in load times when it tried to preload images, stylesheets and other assets. So we are very happy with that optimisation. However, that does not solve my problem. We are going to have to tell the browser in the html which image to download.

The sizes attribute

The browser needs a way to determine which source is best to download. Its best guess is to use the entire width of the browser and go from there. Now, in most cases that will not be optimal, so the sizes attribute was introduced. In the most basic version you can set it to a single value:

<img width="400" height="400" src="/images/fallback-image.png" srcset="/965x1200.jpg 965w, /550x683.jpg 550w, /250x200.jpg 200w" sizes="50vw" alt="Apple Watch">
This image with sizes=50vw tells the browser that we expect the image to take up half of the screen

You can set it to more complicated values, making it use a specific image at a specific media condition

<img width="400" height="400" src="/images/fallback-image.png" srcset="/965x1200.jpg 965w, /550x683.jpg 550w, /250x200.jpg 200w"sizes="(min-width: 600px) 75vw, (min-width: 1024px) 60vw, 50vw" alt="Apple Watch">
This image tells the browser that at 600px or less, the image will be 75% of the viewport, at 1024 60vw and otherwise stick to 50vw.

At the time of writing IMDB and reddit are both using this approach, switching out images when the screensize increases.

The (other) catch

At this point, life is already getting more difficult, however there is one more catch that is gonna ruin everything. The size attribute influences the actual size of the image. I don’t know why this is a thing or who thought of this, but it does. Sizes will act also act as a max-width for your image. So giving your image 100vw, even if the image is big enough, even if it has the space, if sizes is 50vw, it will only use 50vw at most.

Instagram at the moment of writing is using a hack, updating the sizes width of the image to the container width. While trying to implement this myself, I could not make it not brittle. It would randomly keep its size and no longer want to resize.

The only way to get it working is asking the developer for a maximum value that they know will never be reached. At that point, I think this abstraction wouldn’t make sense and would rather leave it up to the developer.

Wrap up

There is no way to create a image component that dynamically handles multiple sources without knowing the width it will be rendered at. Although sad, this is a problem that makes sense. There are proposals being worked on right now that are trying to solve these problems, however for now, there does not seem to be a solution

Resources

https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#how_do_you_create_responsive_images https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/ https://cloudfour.com/thinks/on-container-queries-responsive-images-and-jpeg-xl/

Full overview of how big websites are implementing their images

  • IMDB: uses src-set
  • Wikipedia: only has 1.5x and 2x for retina screens, no different sizes versions
  • Instagram: Changes pixels
  • Whatsapp: unsurprisingly only one version
  • Reddit: src-set with media queries
  • LinkedIn: only one src
  • Twitter: only one src (with dynamic requested resolution)
  • Apple: uses background images to switch images on different viewports

Other resources used

https://stackoverflow.com/questions/38684928/correct-sizes-for-img-srcset-in-a-container-element https://web.dev/responsive-images/ https://www.freecodecamp.org/news/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 https://www.stefanjudis.com/notes/should-responsive-images-work-with-container-queries/ https://stackoverflow.com/questions/37914626/correct-way-to-resize-srcset-images

Arrow Back

View all posts

Hi! I'm Martijn Steenbergen. I am a Software Engineer at bol.com, helping you find what you need. I got my M.Sc. at the wonderful Technical University of Delft. I love automating my life (music, lights, calendar and more). I'm fascinated with design, how the world works and everything else