For a recent project, CookiesHQ had to bring to life a design that contained a lot of images. More images means more data to download when loading the page and in turn, it means an increased loading time before the content gets displayed. This could increase the risk of users leaving the site. Cutting down the number of images would obviously reduce the loading time. But fast loading times have to be balanced with design and marketing objectives, which might still leave a substantial amount of images. The bulk of the effort went on sending browser images with the proper dimensions.

This first article of three, focuses on content images embedded through HTML. Let’s see what we did to prevent loading times from exploding, despite all these images.

The shortcomings of the good ol’ <img> tag.

Since the beginning of HTML, pages could display images thanks to the <img> tag. If you point it at the image to display with its src attribute, you’ll get the picture on the screen. Websites get accessed through devices of various designs and responsive designs cause websites to adapt to these parameters. On a narrow smartphone, an image might take the full width of the screen with some text below. But the design might take advantage of a wider screen, to display the text and image side by side. With its unique src attribute, the <img> tag can only provide one file to download. A small file would look odd on a large screen and a large file will waste bandwidth and increase loading times when loaded on a smartphone.

We needed something to help browsers download the right image for the right aspect.

New standards to the rescue.

In the past few years, a lot of effort has gone into responsive design in regards to imagery and two new standards have emerged to help deal with the situation: srcset and the <picture> element.

As with every new feature, you might wonder about browser support. Modern browsers are happy with both, but if you need support for IE and other older browsers, a battle-tested polyfill is available. However, nothing will break if you don’t include it. The <img> tag will still work as before and use the URL in its src attribute. Users might just end up downloading a few (or lot) more bytes of image than needed.


The new srcset and sizes attributes for the <img> tag.

The first standard brings in two new attributes for the <img> tag: srcset and sizes. As its name suggests, srcset provides a set of sources for the browser to pick from, as a list of URLs with the width (note the w unit in the listing) of the corresponding image.sizes then helps the browser pick the appropriate size. It contains a list of media queries and for each, the image width to use. The width is a CSS length, which means you can take advantage of responsive units like vw or even the calc() function to keep the list manageable. First, matching media query gets picked, so the order is super important.

<!-- Depending on the viewport width, the browser will use the width
     of the matching media query from the sizes attribute to pick the image from the srcset. -->
<img src="default.png"
     srcset="HD.png 1920w, large.png 1280w, medium.png 640w, small.png 320w"
     sizes="(min-width: 1920px) 100vw, (min-width: 768px) 50vw, 100vw" />

Browsers try to download images as soon as they can before the CSS is even applied or loaded. They can’t detect how wide the image will be at this point and need a bit of help. Withsrcset and sizes,browsers can start downloading a unique image with the right width, as soon as they come across the <img> tag. In some parts of the design, we needed completely different images with varying cropping and aspect ratios, to be loaded at different viewport widths. For this, the two attributes were not enough and we needed to rely on another new specification: the <picture> element.

Loading different images with the element.

The <picture> element goes one step further than the srcset and sizes attributes. Wrapping an <img> tag, defines additional <sources> for the browser to pick from, according to media queries or even file formats (which would help serve newer, more compressed image formats to browsers that support them). Each <source> can then define its own srcset and sizes to help the browser pick the right dimensions to load.

<picture>
  <!-- The source will get chosen when the viewport is smaller than 767px.
       Large sources are still needed to catter for high dpi screens.
       No size means the browser considers the image to take the whole viewport. -->
  <source srcset="cropped-large.png 1280w, cropped-med.png 640w, cropped-small.png 320w"
          media ="(max-width: 767px)" />
  <img src="default.png"
       srcset="HD.png 1920w, large.png 1280w, medium.png 640w, small.png 320w"
       sizes="(min-width: 1920px) 100vw, (min-width: 920px) 50vw, 100vw" />
</picture>

Lets put it into practice!

In practice, implementing srcset and <picture> went as follows:

  1. For each image location, we listed the different dimensions at which the image gets displayed across the different resolutions, (without forgetting that high dpi displays would need a 2x image) based on how the CSS was styling them.
  2. For most images however, the width ended “N% of the viewport”. Our backend could only handle so many different sizes of images. Providing images in 1px increments to match wasn’t realistic, so we had to aggregate the sizes to a smaller list. This means some devices will get a slightly larger image than needed, but it’ll be much more maintainable for us.
  3. With this final list, we could then update our Worpdress theme with the thumbnail sizes it needed, so the CMS took care of the resizing for us. Depending on your project, you might go in a different direction to generate the resized images (command line tools, or SaaS like Cloudinary) but it’s a step that can’t be skipped.
  4. Finally, we added the appropriate srcset and sizes attributes to the tags in our theme, along with the necessary <picture> and <sources> elements when needed.

Browsers now had everything they needed to load only the correct image. To verify everything was done correctly, a quick check in the Network panel would tell us if we were actually downloading the size we intended to. The size difference between a full HD or a 375px image that a smartphone will have to download over 3G, is definitely worth it for your users. In turn, it will lessen the risk of your clients losing visits due to sluggish loading time.

Hopefully, this will give you some helpful tips as to how to start implementing responsive images in your HTML. Content images are only half the picture and in a future article, we’ll show you what we set up on the CSS side, to reduce image downloads.

Header by Corinne Kutz on Unsplash

Do you need help creating performant web applications?

Let's have a chat.

Send us an email