1. Web Design
  2. UX/UI
  3. Responsive Design

How to Use HTML5 “picture”, “srcset”, and “sizes” for Responsive Images

Scroll to top

The HTML <picture> element is designed to give us more versatile and performant responsive image functionality. Instead of loading a single image and trying to resize it to suit all possible viewport sizes and layouts, the picture tag loads multiple images of different sizes and resolutions, choosing the best fit for different scenarios.

How Does <picture> Work?

It works similarly to the way <audio> and <video> elements work, allowing you to place multiple source tags within the parent <picture> element, each using the srcset and sizes attributes to specify different image files along with the conditions under which they should be loaded.

However, as powerful as the <picture> element is, sometimes it gives us more power than is actually needed to achieve suitable responsiveness. Sometimes all it really takes is a regular <img> element using the srcset and sizes attributes inline.

Coming up in This Tutorial

In this tutorial we’ll solve any confusion you might have. We’ll see what the srcset and sizes attributes can do, how to use them with an <img> or <picture> element, and how to know which combination is the right choice.

1. Start with a Default <img> Element

an image tagan image tagan image tag

This is our starting point, a regular old vanilla <img> element with an alt attribute to provide a text-based description.

1
<img src="image.png" alt="Image description" />

At the base level of responsive images, this is typically paired with a little bit of CSS that allows this single image to shrink if its parent container becomes too small to hold it:

1
img {
2
    max-width: 100%;
3
    height: auto;
4
}

This does the essential job of making sure the image isn’t sized dramatically incorrectly, but it still leaves us with just one image for all cases, regardless of how well (or poorly) that one image works:

One fluid image for all circumstancesOne fluid image for all circumstancesOne fluid image for all circumstances
One fluid image for all circumstances

It solves the problem in one respect, allowing us to display the same image under many different circumstances. But it doesn’t allow us to specify different images for differing circumstances. For example, it’s quite possible that the original image is impractically large (in terms of file size) for some users to download on their mobile network.

Take a look at What Does My Site Cost? by Tim Kadlec to get an idea of the real cost of mobile data for users all over the world.
“According to the May 1, 2023 run of HTTP Archive, the median site now weighs 2394kb.” – What Does My Site Cost?

Let’s move on to srcset to start working up a better solution.

2. How to Use “srcset” for a Set of Images

Instead of just one image everywhere, it’s much better if we can have a set of images we load depending on the size of the viewport, loading large images for wide and small images for narrow viewports.

That’s what the srcset attribute is for: a set of images rather than just one via the src attribute.

the srcset attributethe srcset attributethe srcset attribute

Width Switching

When an image loads with only a regular src attribute, the browser doesn’t know how wide it is until after it’s loaded. With the srcset attribute, we can tell the browser how wide each of our images is in advance, and it can then use that information to load the most appropriate image depending on the size of the viewport.

You’ll still use the src attribute when using srcset as this provides the default image the browser should use and acts as a fallback if someone uses an old browser that doesn’t support srcset.

Go Mobile First

It’s a good idea to follow a mobile first approach here and load your smallest image via the src attribute. Then add your default image and its larger alternative images inside the srcset attribute as a comma separated list, specifying the width of each, (after a space), with [width]w:

1
<img
2
  src="image-small.png"
3
  srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
4
  alt="Image description"
5
/>

It’s essential to include your default image in the srcset along with its width, despite advice you may have heard to the contrary, or the browser will not include it in the list of options to choose from, so it will never load at any viewport width.

With the above code, the browser will load the small image at small viewport sizes, the medium image at medium viewport sizes, and the large at large viewport sizes. (Describing viewport sizes very roughly).

If the browser doesn’t support srcset, it will fall back to showing the small image. If catering for older browsers is necessary for your projects, including some CSS to scale your default image to the correct size.

Despite the fact the above code will work as is, according to the srcset attribute spec, if you use srcset for width switching, you must also include a sizes attribute, which we will talk about shortly.

Pixel Density Switching

You can also use srcset to load images according to their DPI instead, but instead of specifying their width you should show their pixel density represented as [density]x:

1
<img
2
  src="image-defaultdpi.png"
3
  srcset="image-hidpi.png 2x, image-higherdpi.png 4x"
4
  alt="Image description"
5
/>

However, you cannot use pixel density and width in the same srcset attribute, and you cannot use pixel density specifications with the sizes attribute we are about to add into the mix. For that reason, you are generally more likely to find you’ll want to use width specifications in your srcset attributes.

3. Using “sizes” to Control Image Layout

The sizes attribute allows you to specify a width for the image layout. Note this is a separate concept from the real image widths specified per file in the srcset attribute. The width given in sizes is related solely to layout and can be thought of as creating empty placeholder slots into which the browser can insert images from your srcset.

It doesn’t matter which image file the browser loads from your srcset; it will display it at the width you specified in sizes.

For example, if you wanted your image to always appear at 80% of the width of the viewport, you could use the following:

1
<img
2
  src="image-small.png"
3
  srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
4
  sizes="80vw"
5
  alt="Image description"
6
/>
Percentage values are not allowed, but vw (viewport width) values are.

In this example the browser will still choose between the small, medium and large images depending on the size of the viewport, but whichever image is chosen it will display at a width of 80vw.

Adding Media Conditions

In our example above we used only one value in the sizes attribute, but you can conditionally change up your image layout by adding “media conditions”. Media conditions are the true or false states we evaluate when we use media queries, and when evaluated in sizes allow you lay out your images differently depending on things like viewport width.

For example, we might want an image to be laid out at a width of 80vw so there is some empty space to its left and right, as per our previous example. However we might only want to spare that much of our viewport if it’s sufficiently wide, say a minimum of 60rem.

We can achieve this by changing our code to add the media condition (min-width: 60rem) before our 80vw size, like so:

1
<img
2
  src="image-small.png"
3
  srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
4
  sizes="(min-width: 60rem) 80vw"
5
  alt="Image description"
6
/>

The image will only be sized at 80vw if the viewport is at least 60rem wide.

We can also have our image layout default to a width of 100vw if the viewport does not meet the media condition we just added. Because a default value in sizes doesn’t require a media condition, all we need to do for this is add the 100vw value, after a comma:

1
<img
2
  src="image-small.png"
3
  srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
4
  sizes="(min-width: 60rem) 80vw,

5
100vw"
6
  alt="Image description"
7
/>

If we choose to, we can also add another size and media condition in between, so that as the viewport narrows to 40rem we set the length to 90vw:

1
<img
2
  src="image-small.png"
3
  srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
4
  sizes="(min-width: 60rem) 80vw,

5
(min-width: 40rem) 90vw,

6
100vw"
7
  alt="Image description"
8
/>

The "sizes" Attribute and Image Selection from "srcset."

It’s important to note that regardless of the layout specified using the sizes attribute, the browser will still automatically select the image that best fits the available space, just as it did before we added any media conditions.

While you might come across suggestions to use media conditions in sizes to determine which image should be loaded from the list in your srcset, it’s not the direct functionality of the attribute. It can be misleading to think of it in that way.

In reality, the browser always handles the image selection automatically.

What’s really happening is that with sizes, you’re saying:

“At [this] viewport size I want an image slot [that] wide.”

You’re not specifying a particular image file to load; instead, you’re creating a placeholder "slot" of a specific size to fit your layout.

On the other hand, with srcset, you’re saying:

“Here are my images, pick whichever one you think is best.”

The browser generates empty image "slots" based on the sizes you specified, and then it chooses the most appropriate images from the srcset to fill those slots.

At a glance, the slots’ sizes and the images’ widths may not correspond closely. You might have four images in your srcset, but only two flexibly sized "slots" in your sizes, and yet all four images could be used by the browser at different times.

We observed this in our earlier example, where we created a "slot" size that is active between the 40rem and 60rem viewport width, and it laid out an image with a width of 90vw.

This pixel width of this slot could range anywhere between approximately 570px and 860px. In our example, we provided images at widths of 320px, 800px and 1200px.

The browser will generally selects the smallest image from the srcset that is still wider than the current “slot”. For instance, if the “slot” were at a width of of 810px it would load the 1200px image, but if the slot is 790px wide it would load the 800px image. One media condition, two possible images.

What you specify in sizes influences the image selection from srcset because it changes the size of the "slot" the browser tries to fill. However, these two concepts remain separate and should be considered as such.

In summary:

  1. Consider your image layout as a series of placeholder slots and determine their sizes.
  2. Create images with widths that best fit the slots you defined.

4. When to Use the <picture> Tag

In addition to discussing srcset and sizes, you might be curious about the <picture> element and how it fits into the picture—pun intended.

Harnessing the Power of "Art Direction."

So far, our focus has been on swapping images from a set where the width or pixel density may differ while maintaining the same aspect ratio and orientation. This technique is known as "resolution switching."

However, there are times when you want to go beyond that. Sometimes, you may need to include images with different crops or provide landscape and portrait orientation options.

Introducing "art direction," where the <picture> element steps in, offering an additional layer of responsive image functionality to complement what we’ve explored thus far.

While the <picture> element is perfectly capable of handling resolution switching, it’s advisable to stick with a regular <img> element along with srcset and sizes if that’s all you require. Reserve the <picture> element for situations that demand art direction.

Different images served depending on the circumstances thanks to the picture tagDifferent images served depending on the circumstances thanks to the picture tagDifferent images served depending on the circumstances thanks to the picture tag
Different images served, depending on the circumstances, thanks to the picture tag

Embrace Modern Image Formats

In addition to serving art-directed images, the <picture> element shines when deploying newer image formats such as WebP while gracefully returning to fully supported formats like PNG. We’ll delve into this shortly.

Utilizing the <picture> element allows you to present different images based on specific circumstances—a powerful tool to elevate your responsive image strategy.

5. How to Use <picture>

The <picture> element is not a standalone entity; instead, it is designed to wrap around an <img> element and one or more <source> elements. The purpose of the <source> elements is to provide the browser with additional information to aid in selecting the appropriate file and size for rendering through the <img> element.

To adhere to the requirements of the <picture> element, the <img> element must be its immediate child and should not have its own srcset and sizes attributes. Instead, these functionalities delegate to the <source> element. The <img> element must also have src and alt attributes.

Let’s transform our existing code into the required <picture> format:

1
<picture>
2
    <img src="image-small.png" alt="Image description">
3
</picture>

To reintroduce the functionality we had in our srcset and sizes attribute we can add a <source> element with the same attributes:

1
<picture>
2
  <source
3
    srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
4
    sizes="(min-width: 60rem) 80vw,

5
        (min-width: 40rem) 90vw,

6
        100vw"
7
  />
8
  <img src="image-small.png" alt="Image description" />
9
</picture>

Now that everything functions as before let’s consider that using <picture> solely for resolution switching is unnecessary. Instead, let’s explore a scenario with landscape-oriented images and introduce an entirely new set of images for portrait orientation.

First, we specify that the current set of images should only be used in landscape orientation by adding a media attribute with the value (orientation: landscape) to the <source> element.

We can then repeat that step for (orientation: portrait):

1
<picture>
2
  <source
3
    media="(orientation: landscape)"
4
    srcset="image-small.png 320w, image-medium.png 800w, image-large.png 1200w"
5
    sizes="(min-width: 60rem) 80vw,

6
      (min-width: 40rem) 90vw,

7
      100vw"
8
  />
9
  <source
10
    media="(orientation: portrait)"
11
    srcset="

12
      image-small-portrait.png  160w,

13
      image-medium-portrait.png 400w,

14
      image-large-portrait.png  600w

15
    "
16
    sizes="(min-width: 60rem) 80vw,

17
      (min-width: 40rem) 90vw,

18
      100vw"
19
  />
20
  <img src="image-small.png" alt="Image description" />
21
</picture>

Voila! Now we can have portrait images displayed in portrait orientation and landscape images displayed in landscape orientation. This combination of resolution switching and art direction adds a visually appealing element to our responsive images.

If needed, we can expand on this concept further.

For instance, in addition to regular landscape images, we can introduce <source> elements with a set of wide-landscape images. We can define that these images should be displayed when the site is in landscape orientation and at least 1200px wide using the media attribute: media="(orientation: landscape) and (min-width: 1200px).

Note: While the media and size attributes contain media conditions, they are used differently. The sizes attribute defines a collection of layout sizes, with a layout width specified after each condition. On the other hand, the media attribute contains only a media condition, and only when it evaluates to true does the attached <source> element become active.
Additional Note: It has been suggested that using the media and sizes attributes simultaneously on a <source> element may not be advisable. However, there is no explicit verification of this in the specification, and in my tests, the two attributes appear to work together seamlessly.

Consider <source> Order for Proper Rendering

When constructing <picture> elements, it is crucial to remember the order of <source> elements. The browser will stop evaluating the remaining <source> elements when it encounters one with a media attribute that evaluates to true. Therefore, it is crucial to prioritize media queries with higher specificity by placing them first.

For instance, consider the scenario where we have a <source> element with a media query checking for landscape orientation and a minimum width of 1200px. If you were to place a <source> element that only requires landscape orientation before it, the browser would activate that source and stop further evaluation. To ensure correct behavior, avoid the following arrangement:

1
<picture>
2
  <source media="(orientation: landscape)" ... />
3
  <source media="(orientation: landscape) and (min-width: 1200px)" ... />
4
</picture>

Instead, use the proper order as demonstrated below:

1
<picture>
2
  <source media="(orientation: landscape) and (min-width: 1200px)" ... />
3
  <source media="(orientation: landscape)" ... />
4
</picture>

By correctly arranging the <source> elements, you ensure that the browser follows the intended logic and selects the appropriate source based on the specified conditions.

Using <picture> for Partially Supported File Types

The fact that <picture> will go through a stack of <source> elements until it finds an image it can load successfully means you can use it quite handily to load newer file formats that don’t have 100% browser support yet.

In this example, if WebP is supported in the browser it will load as it’s specified in the first <source> element. If the browser cannot load the WebP image it will attempt to load the SVG from the second <source> element. And finally if neither are supported, the PNG will load instead:

1
<picture>
2
  <source type="image/webp" srcset="illustration.webp">
3
  <source type="image/svg+xml" srcset="illustration.svg"> 
4
  <img src="illustration.png" alt="A hand-made illustration">
5
</picture>

You’ll notice that in this example the type attribute is used. When loading alternate file formats through <picture> you should specify the MIME type in this way to allow the browser to instantly check on file type support as soon as it hits the <source> element in question.

A Note on Accessibility

Screen readers will use the alt text supplied in the fallback <img> element for whichever image is displayed in the browser. Make sure, therefore, that the alt text represents all the images equally well!

6. Browser Support for <picture>

Browser support for the <picture> element is very solid nowadays, though like many other aspects of modern CSS and HTML Microsoft lean on the Edge browser, rather than IE, to fly the team colors.

Browser support for picture elementBrowser support for picture elementBrowser support for picture element

By using the fallback <img> tag within <picture> you’re still catering for anyone using a non-supporting browser.

Conclusion

Between srcset, sizes and <picture> we have incredibly robust and extensive control over your responsive images, as well as the ability bringing new file formats onto the stage with graceful degradation.

Useful Resources

To learn more about the <picture> element and its usage within HTML, you can explore the following resources:

  • HTML Living Standard - <picture> : The HTML Living Standard is the official specification for HTML.
  • srcset - More documentation and specifications for the srcset attribute.
  • sizes - More documentation and specifications for the sizes attribute.

Try out srcset, sizes and <picture> in your project today and see what you think!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.