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:
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
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:
You can set it to more complicated values, making it use a specific image at a specific media condition
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