A picture element to load correctly resized webp images in HTML
- Published at
- Updated at
- Reading time
tl;dr – I have trouble remembering (and finding) the complete HTML snippet to load responsive
webp images. You (and future me) find the snippet below.
Loading images in the best sizes and formats was always complicated. With the Avif image format around the corner, there is one more format to consider, and shipping images is not getting any easier. Developers have to choose between traditional image formats like
jpeg, the almost mainstream
webp format, the new
avif image format, and many others.
The browser-support of the available options varies greatly:
- traditional image formats (
jpeg, and others) are fully supported
webpis nearly full browser supported
avifis only supported in Chrome.
If you decide to ship
webp or even
avif, you have to consider a loading strategy that works for your users and falls back to image variants for browsers that don't support the new and shiny.
Approaches to load new image formats
Accept header of image requests and respond with the best image format (a browser that supports
webp includes an HTTP header that looks like
If you prefer an HTML-only solution, you can leverage responsive images and the picture element to load the best image format.
After searching snippets that cover ways to load
webp using the
picture element countless times, I know that there are many materials out there. But unfortunately, very few articles go further than scratching the surface. Most tutorials show only how to load the
webp format and forget the rest.
Let's have a look at the snippet below. It's the first step to load a
<picture> <!-- load avif if supported --> <source srcset="img/image.avif" type="image/avif"> <!-- load webp if supported --> <source srcset="img/image.webp" type="image/webp"> <!-- load in case no `source` format applies and use attributes for presentation --> <img src="img/image.jpg" alt="Alt Text!"> </picture>
This snippet loads
avif images when the browser supports them. Otherwise it loads a
jpeg. Great stuff; job done!
Not so quickly! This
picture element is not taking pixel density, device size, or CSS layout into consideration. When you're ignoring layout and image dimensions and load a 3500px wide image on a phone with a slow connection, no image format in the world will save all the wasted data and computation.
A more complete snippet that I wrote to load responsive
webp images from the Contentful Images API looks like the following. The beauty of using an Image API is that you can upload an image and request different formats using query parameters (
fm=webp automatically converts the image to
<picture> <!-- load webp images if supported --> <source type="image/webp" srcset=" https://images.ctfassets.net/.../paris.jpg?w=100&fm=webp 100w, https://images.ctfassets.net/.../paris.jpg?w=200&fm=webp 200w, ..." sizes=" (max-width: 768px) calc(100vw - 3em), (max-width: 1376px) calc(50vw - 8em), 550px"> <!-- load traditional supported image format --> <img srcset=" https://images.ctfassets.net/.../paris.jpg?w=100&fm=jpg&fl=progressive 100w, https://images.ctfassets.net/.../paris.jpg?w=200&fm=jpg&fl=progressive 200w, ..." sizes=" (max-width: 768px) calc(100vw - 3em), (max-width: 1376px) calc(50vw - 8em), 550px" src="https://images.ctfassets.net/.../paris.jpg" alt="Buildings of Paris" loading="lazy" decoding="async" width="1243" height="1500"> </picture>
This snippet is a mouth full (and I can not say that I enjoy writing this HTML).
source elements include not only a
type attribute but also
sizes. These two attributes are core parts of responsive images and can be applied to the source element, too.
sizes give additional layout and source URL information so that the browser can load properly sized images depending on screen size and other factors. This
picture element loads not only the best format but also images in the best sizes.
img element includes more attributes. Be aware that the included
img is not only the
picture's fallback solution. The
source elements' job is to augment and provide additional source information about this one included image.
Even though there is a
picture element around the image, you still have to consider image best practices to provide the best user experience:
alt– define alternative text for assistive technology or in case the image doesn't load
loading– define an image lazy loading strategy
decoding– define an image decoding strategy
height– provide an aspect ratio to avoid layout shifts
Every time I write an element like the one above, I wonder if it has to be that hard. That's so many keystrokes for a problem that could be solved by the web platform itself. Maybe, I'll open a proposal someday, but I bet someone already did that. 🙈
Have a look at the following resources to learn more about the best way of loading responsive images.
- Malte Ubl shared ways to optimize images to the extent
- The Next.js framework started abstracting all image best practices in an
Imagecomponent. It's a promising approach for sure!
Pssst... If you like this post, I send a weekly newsletter including all kinds of web development tricks. 😉
- Safari only supports image formats macOS/iOS support, and that's good for some users
- Automatic hyphenation depends on the defined document language
- Input-wrapping labels are not supported by Dragon
- How to define Open Graph / Twitter image alt text (and why it might not matter...)
- "HTML End Tag Labels" – a useful VSCode extension to navigate HTML