A quick guide to responsive images

Responsive design is more than seven years old now. And it arguably arrived just in time. As the capabilities of mobile and tablet devices grew, it no longer made sense just to think in terms of a desktop or mobile website. The age of the m dot website was coming to an end, making way for a brave new world of content that reflowed depending on the viewport.

The trouble was, web standards weren’t quite ready, especially when it came to images. The problem wasn’t so much with background images. These could be selected according to viewport width and screen resolution with CSS media queries. But images in the HTML, as <img> elements, were another matter. Web developers were forced to resort to one of three unsatisfactory options:

  1. Scaling a single, big image down to fit the viewport, cropping if necessary. Ironically, this process is particularly resource-intensive on the mobile devices it’s supposed to cater for.
  2. Redefining <img> elements as background images to take advantage of media queries. This is less than ideal semantically, but also means the image is likely to be discovered (and therefore displayed) later – unlike <img> elements, background images won’t be found by the browser preloader.
  3. Using JavaScript to detect viewport width and use the most appropriate image. While there are some excellent solutions out there, the extra overhead still slows down the selection and delivery of the right image. Once again, this tends to be slower on less capable mobile devices.

Then the web caught up. The responsive images specification was born. Now we can use <picture>, <source> and srcset to deliver responsive images in the HTML. And browser support is, at last, pretty much universal.

However, it’s not exactly straightforward. Although the spec is very flexible, it pays for its power with its complexity.

So here’s a simple guide to cater for some of the more common requirements.

1: My hero image takes up the entire viewport width on all devices. It’s the same image, and I just want to deliver the right size version for the viewport.

This one is pretty easy to do:

<img src="hero-large.jpg" alt="" sizes="100vw"
srcset="hero-small.jpg 360w, hero-medium.jpg 720w, hero-large.jpg 1024w, hero-v-large.jpg 1400w">

Here, we’re just using the srcset attribute in the <img> element to give the browser some options. It can pick from four images. One is 360 pixels wide (360w), one is 720 pixels wide (720w) and so on.

The sizes attribute tells the browser that we’ll need the image to be displayed at 100 per cent of viewport width.

Finally, we have the mandatory src attribute, which is also a handy fallback for any browsers that don’t support srcset.

The clever thing about srcset is that it automatically takes device pixel ratio into account, so you can display higher quality images on high-resolution screens.

The example below shows how the above code works on an iPhone 5, with a device pixel ratio of 2. Here, the viewport width is 320 pixels, but the high-resolution display can squeeze in double this amount. So instead of picking the 360 pixel wide image, the browser selects the 720 pixel version (320 x 2 = 640, which is closer to 720 than 360).

Fortunately, you don’t really need to worry about this. You can just rest easy knowing the browser has taken care of it for you.

2: I want to do exactly the same as the above, but this time I need the image to take up half the viewport width if the viewport is wider than 768 pixels.

This time, you just need to tweak the last example and add a media query to the sizes attribute. The changes are highlighted below:

<img src="hero-large.jpg" alt="" sizes="(min-width: 768px) 50vw, 100vw"
 srcset="hero-small.jpg 360w, hero-medium.jpg 720w, hero-large.jpg 1024w, hero-v-large.jpg 1400w">

3: My design is very different on mobile, and I need different images. I don’t really care about delivering high-resolution images to devices with high device pixel ratios.

If you want to dictate to the browser which image to use at which viewport, use a combination of <picture> and <source>.

If the media query in the <source> element is met, the browser will look to the srcset within the <source>. If not, it will keep going until it finds a media query that matches, falling back on the <img> element if none do.

In the following example, hero-large.jpg will be used if the viewport is at least 768 pixels wide. Smaller viewports will use hero-mobile.jpg.

<picture>
<source media="(min-width: 768px)" srcset="hero-large.jpg">
<img src="hero-mobile.jpg" alt="">
</picture>

You’re not taking device pixel ratio into account this time, so high-resolution displays will get a standard sized image. High-resolution images are bigger and slower to load, so if your top priority is making your site fast on mobile, this is the one to go for.

Here’s how it looks on the iPhone 5:

4: The same as the previous example, but this time I’d like to take advantage of high-resolution displays. I’d also like to display the image at half the viewport width for displays over 768 pixels wide.

This is a bit like combining the last two examples. We’ve added some alternative images in srcset attributes and let the browser know the size they’ll be needed at, using the sizes attribute. The changes are highlighted in the example below:

<picture>
<source media="(min-width: 768px)"
srcset="hero-large.jpg 1024w, hero-v-large.jpg 1400w" sizes="50vw">
<img src="hero-mobile.jpg" sizes="100vw" srcset="hero-mobile-hi-res.jpg 720w" alt="">
</picture>

Heading back to our iPhone 5, you can see that a higher resolution version is selected:

There is more.

I haven’t gone into using this spec to switch between different image formats, talked about Client Hints or gone into the third-party services that do the work for you.

But I’ll save those for a future post.

This short guide is all about simple solutions for the most common use-cases, and I hope it’s helpful!

Published date:  31 October 2017

Written by:  Alex Painter

comments powered by Disqus

Filter By Service

Filter By Date