Asking for a Friend: Responsive Images

Dear reader, you are a person of culture, you know the in-and-outs of front-end web development like the back of you hand. But, face it, not everyone is as well informed as you! Perhaps you have an acquaintance who is trying to become more well read on these things, self improvement is commendable, but - gosh - you simple don't have the time to learn them in the ways, teach them to walk the path of proper front-end development. Well friend, we have a bit of time, send them over and let's begin our discussion of todays topic: Responsive Image Solutions!

Responsive image techniques, such as the srcset, sizes, and media HTML attributes, allow different scaled images to be delivered based on the size and resolution of the accessing device. This allows you to further optimize your image delivery to improve the overall performance of your website or application.

Instead of taking a single image and only making it responsive with CSS, which is then delivered to all devices, you can deliver completely different images based on the requesting device. This is advantageous because of the significant performance improvements that can be gained.

Adding Attributes: srcset, sizes, & media

The srcset, sizes, and media attributes allow the and elements to be extended by offering the browser additional information, such as different image sources as well as different display sizes and media conditions. This offers browsers the ability to display a specific image when a rule is met.

So, a srcset attribute allows image sources to be defined. This can be done by defining the absolute or relative path to the images and optionally the pixel density descriptors (e.g. 1x, 2x, and 3x). This attribute can be used in the and elements.

Both sizes and media attributes are nearly identical. Both allow different display sizes to be defined through various media conditions. But, the sizes attribute allows an image size to defined either alone or in relation to a media condition. The sizes attribute can be used in the and elements, when the media attribute can be used in the element but not the element.

In all cases the element needs to be a directly within the element.

Using srcset, sizes, and media

To cover the basics, all that is actually required to insert an image is the tag and src attribute, for example:

<img src="/img/blog/some-image.png">

The src attribute will let the browser know where to make the image request. If an absolute path is defined, as shown above, the browser will make a request using the scheme and hostname of website where the element is placed.

The width and height attributes can define src size, but this could lead to an image larger than the device viewing it. That is why it is common to see the class attribute to style the image instead, for example:

<img src="/img/blog/some-image.png" alt="some image" class="img-responsive">

Sadly, using the element above will result in a single image being delivered across all devices. While using CSS to scale the image to fit across all devices does make the image responsive, which in our case is accomplished by using the img-responsive class, this would lead to a significant amount of unnecessary data being delivered. Serving an unscaled image will slow performance, increase the overall page size, and waste bandwidth. And so this is where the responsive srcset, sizes, and media attributes come to the rescue.

Using srcset

The srcset attribute can be used in the and elements. We simply add the width of the images after the file name, such as 730w, 610w, and 350w. However the problem with this method is that you are relying solely on the size of the viewport to tell the browser which image to load, for example:

<img
    srcset="/img/blog/some-image-lg.png 730w,
    /img/blog/some-image-md.png 610w,
    /img/blog/some-image-sm.png 350w"
    src="/img/blog/reponsive-images.png"
    alt="some image"
>
<picture>
    <source srcset="/img/blog/some-image-lg.png 730w">
    <source srcset="/img/blog/some-image-md.png 610w">
    <source srcset="/img/blog/some-image-sm.png 350w">
    <img src="/img/blog/reponsive-images.png" alt="some image" class="img-responsive">
</picture>

Luckily for us, this is where the sizes and media attributes comes into play.

Using sizes

The sizes attribute tells the browser exactly what size the image will be in relation to the size of the viewport through media conditions, which are similar to media queries. This can be used in conjunction with the srcset, for example:

<img
    sizes="(min-width: 1200px) 730w, (max-width: 1199px) 610w, (max-width: 380px) 350w"
    srcset="/img/blog/some-image-lg.png 730w, /img/blog/some-image-md.png 610w, /img/blog/some-image-sm.png 350w"
    src="/img/blog/reponsive-images.png"
    alt="some image"
>
<picture>
    <source sizes="(min-width: 1200px) 730w" srcset="/img/blog/some-image-lg.png 730w">
    <source sizes="(max-width: 1199px) 610w" srcset="/img/blog/some-image-md.png 610w">
    <source sizes="(max-width: 380px) 350w" srcset="/img/blog/some-image-sm.png 350w">
    <img src="/img/blog/reponsive-images.png" alt="some image" class="img-responsive">
</picture>

The sizes attribute is very helpful when using the element, however, if you are using the element it is often makes more sense to use the media attribute instead.

Using media

The media attribute allows a media condition to be defined. This can be used in the element if its a direct child of the element. If the condition is true that element is used, if false it is skipped, for example:

<picture>
    <source media="(min-width: 1200px)" srcset="/img/blog/some-image-lg.png">
    <source media="(max-width: 1199px)" srcset="/img/blog/some-image-md.png">
    <source media="(max-width: 380px)" srcset="/img/blog/some-image-sm.png">
    <img src="/img/blog/reponsive-images.png" alt="some image" class="img-responsive">
</picture>

In addition to being able to define what image is used based on the viewport size, it is also possible to define what image is used based on the pixel density of the display.

Pixel Density Descriptors

The pixel density descriptors, also referred to as display or screen density descriptors, are an extremely helpful way of displaying high resolution images on high resolution displays. These descriptors are defined using 1x, 2x, and 3x. They allow an image to be displayed that is either two or three times larger than the original while retaining the same dimensions as the original image, for example:

<img
    sizes="(min-width: 1200px) 730w, (max-width: 1199px) 610w, (max-width: 380px) 350w"
    srcset="/img/blog/some-image-lg.png 730w 1x,
    /img/blog/some-image-lg@2x.png 730w 2x,
    /img/blog/some-image-md.png 610w 1x,
    /img/blog/some-image-md@2x.png 610w 2x,
    /img/blog/some-image-sm.png 350w 1x,
    /img/blog/some-image-sm@2x.png 350w 2x"
    src="/img/blog/reponsive-images.png"
    alt="some image"
>
<picture>
    <source media="(min-width: 1200px)" srcset="/img/blog/some-image-lg.png 1x, /img/blog/some-image-lg@2x.png 2x">
    <source media="(max-width: 1199px)" srcset="/img/blog/some-image-md.png 1x, /img/blog/some-image-md@2x.png 2x">
    <source media="(max-width: 380px)" srcset="/img/blog/some-image-sm.png 1x, /img/blog/some-image-sm@2x.png 2x">
    <img src="/img/blog/reponsive-images.png" alt="some image" class="img-responsive">
</picture>

The sizes or media attributes are not required when using the pixel density descriptors, however, the actual 2x or 3x image does need to be two or three times larger. You can reduce the size of the scaled images even further by using the next generation image format, WebP.

The WebP Format

Lastly, lets talk about file formats. WebP is the newest format and WebP formatted images are (on average) 26% smaller than PNG formatted images and 25-34% smaller than JPEG formatted images! Winning! This means just converting your images to WebP can decrease the size of your pages by about 25%. Now, WebP formatted images are not yet accepted by every browser, which is where the type attribute becomes useful in the element, for example:

<picture>
    <source type="image/webp" media="(min-width: 1200px)" srcset="/img/blog/some-image-lg.webp 1x, /img/blog/some-image-lg@2x.webp 2x">
    <source type="image/webp" media="(max-width: 1199px)" srcset="/img/blog/some-image-md.webp 1x, /img/blog/some-image-md@2x.webp 2x">
    <source type="image/webp" media="(max-width: 380px)" srcset="/img/blog/some-image-sm.webp 1x, /img/blog/some-image-sm@2x.webp 2x">
    <source type="image/png" media="(min-width: 1200px)" srcset="/img/blog/some-image-lg.png 1x, /img/blog/some-image-lg@2x.png 2x">
    <source type="image/png" media="(max-width: 1199px)" srcset="/img/blog/some-image-md.png 1x, /img/blog/some-image-md@2x.png 2x">
    <source type="image/png" media="(max-width: 380px)" srcset="/img/blog/some-image-sm.png 1x, /img/blog/some-image-sm@2x.png 2x">
    <img src="/img/blog/reponsive-images.png" alt="some image" class="img-responsive">
</picture>

As we have said, the will only be used if the condition is true, which means in our example above the WebP images will be used where accepted, PNG images will be used where WebP images are not accepted, and if all else fails the element will be used. The class applied to the image used in the element will be pulled from class attribute in the element.

Browser Support Matters

Most modern web browsers now support srcset, except Internet Explorer and Opera Mini. However, Microsoft did add support for this attribute in the Edge browser. If the browser does not support this attribute, the browser will simply fallback to the original image. If using the tag the fallback image is defined in the src attribute. If using the element the fallback image is defined in the element. This means there really is no disadvantage to using the attributes from a browser perspective.

The Importance of Responsive Images

The reason responsive images are so important all comes down to file sizes. On smaller devices, there is no reason to download an image that is 1460 x 730 pixels. It is a waste of bandwidth and resources. How much of a waste? We can take a look at the image sizes we used in the examples above, for example:

  1. some-image.jpg (30.7 KB)
  2. some-image-lg.jpg (24.1 KB)
  3. some-image-md.jpg (19.7 KB)
  4. some-image-sm.jpg (10.6 KB)

If a small device, such as a phone, has a display size of 375 pixels, serving the scaled some-image-sm.jpg image would be 10.6 KB. If we compare that to the original unscaled some-image.jpg image (which CSS would have to scale down) at 30.7 KB, that is a decrease of 65.47%! This will vary depending on whether or not pixel density descriptors are used, however, serving scaled images will always reduce the overall page weight.

With more complex and higher resolution images you would likely have an even higher decrease. Furthermore, over time this can save quite a bit of bandwidth from your hosting or CDN provider, which in turn saves you money.