Home Articles Categories Series
Pythonise Just now
More from this series
Recommended learning

Faster image loading with the picture element | SEO & performance Pt. 2

Using the HTML picture element to render the best image for the users device & serve next gen image formats

Article Posted on by in Flask
Julian Nash · 2 years ago in Flask

When it comes to website performance, images are often the primary cause of slow load times.

The fact is that now more than ever, we're accessing the web from a wide range of devices, from smarphones & tablets to desktops and TV's, all of which means we need to think smarter about how we serve images on the web.

Not only are users frustrated when faced with slow loading images, SEO takes a hit too, with Google and co frowning upon slow load times, especially when observed in a page speed reporting tool such as Lighthouse.

In this article, we're going to take a quick look at the HTML <picture> element, a tag introduced around 2014 to the HTML specification which (amongst other things) let's us render a specific image to a client, based on their viewport/device.

HTML img tag

To render an image, it's very common to use an img tag, such as:

<img class="img" src="img/example/example.png" alt="Just an example">

This works just fine and coupled with some basic CSS, will render a scaled, full width image on most devices:

.img {
  display: block;
  width: 100%    

For example, let's say example.png is a 2560 x 1440px image, the browser will scale the image down and maintain the aspect ratio to display it on smaller devices.

Again, this works just fine, however:

  • The size of the image/request remains the same across all devices
  • The browser uses computational resources to resize and scale down the image

This may not be too much of an issue if you're only displaying a single image on a page, but what if you've got more than one image? Those large image requests quickly start to add up.

Even if the client is viewing the page from a mobile device, the browser will request a 2560 x 1440px image and downscale it to fit the users viewport! Wasting valuable bandwidth and computational resources, ultimately slowing down your page load time.

This is where the <picture> tag comes into play.

HTML picture tag

The <picture> element was introduced to the HTML starndard a few years ago now, however I don't see it being used all that often.

It allows us to specify a range of different images and let the browser decide the correct image to display, depending on the clients viewport (along with a couple more things that we're not covering in this guide).

You can see the basic syntax of the <picture> element in the example below:

  <source srcset="/img/example/example-540.png" media="(max-width: 540px)">
  <source srcset="/img/example/example-768.png" media="(max-width: 768px)">
  <source srcset="/img/example/example-1080.png" media="(max-width: 1080px)">
  <source srcset="/img/example/example-1200.png" media="(max-width: 1200px)">
  <img src="/img/example/example.png" alt="Just an example"/>

The <picture> element contains two different tags; <source> and <img>.

<source> tags can have the following attributes:

  • srcset - A URI of an image
  • media - Any valid media query (as used in CSS)
  • sizes - A width descriptor (not covered in this guide)
  • type - The MIME type of the resource

The <img> tag is required as the last tag in the <picture> element and is used as a fallback for backwards compatibility and if none of the media queries are matched.

How it works

The browser will start at the first child of the <picture> element and will render the image if the media query matches.

In the case of our above example:

  • On a mobile device (max-width: 540px) - The browser will render example-540.png.
  • On a tablet device (max-width: 768px) - The browser will render example-768.png.
  • On a larger tablet (max-width: 1080px) - The browser will render example-1080.png.
  • On a device with a viewport greater than 1200px - The browser will fall back to the <img> tag and render example.png.

This means that we can serve images of a much closer size to the users viewport, reducing the size of the request and increasing load times. Another common use case for the <picture> tag is for art direction & user experience, serving a different image depending on the clients device.

Next gen images

In the above example, we're serving images of the same file type (png).

Next gen image formats including webp are emerging standards for images on the web, offering high quality compression and dramatically reduced file sizes.

Sounds good right? However, not all browsers offer support for all of the next gen image formats.

To combat the cross browser compatibility issue, we can use the <picture> element, combines with the type attribute in the child <source> tags.

It's probably better explained with the example below:


  <source class="img" srcset="/img/example/example-thumbnail.webp" type="image/webp" media="(max-width: 150px)">
  <source class="img" srcset="/img/example/example-thumbnail.png" type="image/png" media="(max-width: 150px)">

  <source class="img" srcset="/img/example/example-540.webp" type="image/webp" media="(max-width: 540px)">
  <source class="img" srcset="/img/example/example-540.png" type="image/png" media="(max-width: 540px)">

  <source class="img" srcset="/img/example/example-768.webp" type="image/webp" media="(max-width: 768px)">
  <source class="img" srcset="/img/example/example-768.png" type="image/png" media="(max-width: 768px)">

  <source class="img" srcset="/img/example/example-1080.webp" type="image/webp" media="(max-width: 1080px)">
  <source class="img" srcset="/img/example/example-1080.png" type="image/png" media="(max-width: 1080px)">

  <source class="img" srcset="/img/example/example-1200.webp" type="image/webp" media="(max-width: 1200px)">
  <source class="img" srcset="/img/example/example-1200.png" type="image/png" media="(max-width: 1200px)">

  <source class="img" srcset="/img/example/example.webp" type="image/webp" media="(min-width: 1200px)">
  <img class="img" src="/img/example/example.png" alt="Just an example" />


In this example, we've added an additional 6 <source> tags to our picture element using type="image/webp".

The browser will only load the webp images if the browser supports it, otherwise falling back to the png image just below it.

The img class is only used for styling and contains no media queries. We're leaving it to the browser to select the most appropriate image for us, depending on the clients device.


To see the <picture> tag in action, open the developer tools and click on the network tab, selecting the img button to filter the requests and only show images.

Set the viewport to responsive and drag the width to the smallest it will go.

Hit reload and slowly increase the width of the viewport.

As you drag out the width of the viewport, you'll see images being requested as the media queries in the <source> tags are matched!

Set the viewport to a specific device and reload the page to see what image the browser decides to load.

Wrapping up

This was just a quick introduction to the HTML <picture> element, to demonstrate a couple of use cases which offer immidiate performance upgrades to your site load times and SEO.

Check out the detailed guide on html5rocks to explore more features and use cases of the <picture> element.

Last modified · 14 Mar 2019
Did you find this article useful?
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License