Author image
Senior Consultant

Responsive images with srcset and sizes

Responsive design is now the norm when it comes to developing modern websites, and most of us will be all too familiar with how we use media queries to get our sites looking different on a whole range of different devices. When it comes to getting our images to resize depending on the viewport / device, we now have two options: we can again rely on media queries, or we can use the srcset and sizes attributes that were defined in the <picture> element specification. It is the second option that we’ll be looking at in this article to see how it is much better suited to responsive images.

Why not use media queries

Before we get into the details of srcset and sizes it perhaps serves to take a bit of time to consider why media queries aren’t the best tool for the job when it comes to images. Put simply, it has to do with the number of variables the browser needs to know to load the correct image and when these variable become known to it. A browser will know everything about the environment within which it is rendering a website i.e. the size of the viewport and the resolution of the user’s screen; however, it won’t know the size of the image relative to the viewport or the dimensions of the image it has to render.

The reason for this is simply down to when the browser tries to load each resource: it kicks off the download of any image files before it has fully downloaded any CSS or JavaScript code meaning at the point it tries to download the image files it doesn’t know everything it needs to know to download the correct resolution image.

To solve this problem with media queries we would have to write a new rule for each permutation, which very quickly becomes laborious and is obviously prone to error not to mention it is far from being future proof. This is where srcset and sizes come in; what we are essentially doing is telling the browser the things it doesn’t know so it can go away and select the correct image to download. Basically we get the browser to do all the heavy lifting for us!

img versus picture tags

The srcset and sizes functionality gets defined in the picture tag but also works with the img tag as we'll show below. The key thing to note here however, is that the two tags aren't exactly interchangeable. With the picture tag you are telling the browser exactly what to do, and it will naively follow the conditions you specify. However, when you use the img tag you are giving it a lot of different images to choose from, and letting the browser make the final decision on the best one to use.

A good example of this would be a large screen that has a high resolution, something like the iPad Pro. If we were to use the picture tag we could (rightly) say that it should load a large image to render on this display. However, what we don't know when we specify this is the speed of the user's connection, as this is something that only the browser knows, so it may not always be sensible to load that large, high resolution image. If we were to use the img tag along with srcset and sizes, we would let the browser choose the best image to load. The browser would then detect the user's connection speed and automatically swap out that nicer, larger image for something more appropriate.

srcset and sizes

Let's look first at the srcset attribute. This attribute allows us to define a comma separated list of image files and the widths of these files (since the width is the bit the browser doesn’t know when it downloads the image). The syntax for this is as follows:

<img src=”example.jpg” alt=”example”
  srcset=”example-160.jpg 160w,
            example-320.jpg 320w,
            example-640.jpg 640w,
            example-1280.jpg 1280w”>

The syntax is reasonably self explanatory; if we look at the first line of the srcset attribute, we can see that we specify a file called example-160.jpg which has a width of 160 pixels.

Next we come to the second bit of information the browser doesn’t know: the size of the image relative to the viewport. Without this the browser still doesn’t have everything it needs in order to select the correct image to render. This is where we make use of sizes.

Without specifying a sizes attribute, srcset with widths doesn’t really make very much sense. So let’s use the above example again, but this time we’ll include the sizes attribute so we can see how it all ties together:

<img src=”example.jpg” alt=”example”
  srcset=”example-160.jpg 160w,
            example-320.jpg 320w,
            example-640.jpg 640w,
            example-1280.jpg 1280w”
  sizes=”(max-width: 480px) 100vw,
            (max-width: 900px) 33vw,
            250px”>

The first thing you’ll notice is the sizes attribute also takes a comma separated list of values, with each value specifying the size of the image relative to the viewport. This is the key thing to understand when it comes to sizes - it’s how we tell the browser the size of the image relative to the viewport, and thus how to choose which image to use.

Let’s dissect the first item in our comma separated list of sizes to see what’s going on. We start with a media query of (max-width: 480px). The second thing that’s included is 100vw. Here, the vw unit just stands for viewport width and represents the percentage of the viewport you want the image to occupy.

The browser can then download an appropriately sized image for the viewport size, and CSS can then tidy things up and get it rendering exactly as wanted. So in this example 100vw mean the image should be 100% of the width of the viewport and in the second value of (max-width: 900px) 33vw the image will be 33% the width of the viewport. You’ll notice that in the final value we just specify a fixed width of 250px, this is just to show that we can use fixed widths as well as <code<vw values to specify the size.

Each media query defined in sizes is evaluated in order, and the first one that matches is the one whose associated width is taken. So in the above example we could roughly say for the purpose of this example that:

  • On devices with a width of 480px or less show a image that is 100% the width of the viewport
  • On devices with a width greater than 480px but 900px or less show an image that is 33% of the width of the viewport.
  • On devices with a width greater than 900px show a fixed width image of 250px.

And that’s basically all there is to srcset and sizes, the browser now knows everything it needs to know in order for it to select the best size image for the device it’s being rendered on. The browser will already know the other things it needs in order to select the best image such as the screen density and the size of the viewport and we tell it the things it doesn’t know i.e. the size of the image relative to the viewport and the width of each image it has available to it. All this enables the browser to do much of the heavy lifting associated with responsive images.

In a future article we'll show you some Drupal modules that can help you implement srcset and sizes, and talk through a custom implementation.