Improving Performance by Using Responsive Images

Ezgi Urkmez
Cazoo Technology Blog
4 min readMay 6, 2021

Images generally consume the most bandwidth when loading a page or application. Therefore image optimisations can play a critical role in improving the performance of a website. By targeting large images and making use of responsive image techniques, it’s possible to significantly improve load times and performance.

User browsing a website on multiple devices

Responsive Images

Our main goal is to improve the performance so users have a better experience when browsing Cazoo. By using <img> tags to serve different sizes of the same image as well as picture elements of use-cases where the aspect ratio changes across devices, we can retain strict design control.

We identified that images on the Cazoo View were not optimised, giving the user a very large hero image as well as images that flowed through the body of the article.

We observed poor performance scores on the Google Lighthouse audit tool and webpage tests. On closer inspection, we identified opportunities to improve Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS) and Time To Interactive (TTI) as well as Core/Other Web Vitals.

We prioritised improving Largest Contentful Paint because it indicates a good loading experience. Using Treo as our monitoring tool that records Core and Other web vitals on an hourly basis, we could easily draw comparisons of before and after optimisations.

Implementation

Applied a picture element to the hero

  • The hero image is the large full-width image at the top of the page. It takes up a majority of the above-the-fold content. It’s therefore really important that it loads as quickly as possible. We applied a picture element because the image changed aspect ratio at different viewports. This intentional changing of the image is usually called “art direction.”
  • We worked with the headless CMS (Prismic) to define multiple crops of the same image. The engineers can also control the dimensions of each crop to avoid unnecessarily large images being used.
  • We will have a separate blogpost about using responsive image tags. Stay tuned :)

Optimised all image sizes and formats

  • Reduce image sizes

CDN is one of the best ways to optimise images. As a CDN solution we are using Cloudinary. If a URL of an image is loaded from Cloudinary, it carries some information, like origin, image, security key and transformation. Some information from the image and transformation part can help us to parameterise the size, format and quality. We can use different formats of the image for different viewports.

  • Lazy loaded images below the fold

As we mentioned above, the portion of media resources on our site was really big and we also have lots of inline images in our content pages and homepage. First of all we didn’t consider reducing the number of images and videos on the pages. As a solution to the problem, we chose a relatively uncontroversial technique and started lazy loading images to improve initial page load time and reduce initial downloaded items size and system resource usage.

What is lazy loading ?

It is a method that delays loading required resources until the component comes into view. If we need to translate the description in real life it looks something like this:

  • You land on a site/page and start scrolling down to see more content
  • Then new components comes into view and it loads critical/required resources
  • Then the image component is rendered with the final image

We all talked about the performance benefit of lazy loading. It also helps us not to waste user’s data for downloading resources that are not going to be seen by the user.

How to detect when an element comes into view

As we discussed earlier, lazy loading is all about deciding what resources are critical or non-critical. We have some options here:

  • using browser-level lazy loading — This is done with using loading attribute in the image tag like this <img loading=lazy>
  • using scroll and resize event handler
  • using an intersection observer

We choose to use intersection-observer which provides a way for us to asynchronously observe changes in the visibility of our components.

Although it’s unsupported on IE11, we chose to use intersection-observer with a fallback polyfill because it’s a relatively clean and testable way of asserting if an element is in the viewport.

How to avoid layout shifts when lazy loading images

When you start lazy loading images, you’d quickly realise that it causes big layout shifts when the image starts loading. To avoid this problem, you can setup a container div around the image that takes up the same space as the image (when it’s loaded). This would mean that the content around the image would stay in place when the image is loaded.

One example implementation of such a div is like this:

If you want to check out the implementation, disable your cache and throttle network speed (like slow 3G) in the network tab of the dev tools.

Measuring Improvement

Core Web Vitals

  • Largest Contentful Paint(LCP)

It was the most important metric for us to see how page load timeline changed with our improvements. This metric measures the render time of the largest item in the view. Having a good LCP score for your page is a sign of good user-experience.

  • Cumulative Layout Shift(CLS)

CLS metric observes the unexpected behaviour of page content. For us, unexpected behaviour could be images on the page not loading on time when the image placeholder comes into view.

Other Web Vitals

  • Time to Interactive(TTI)

It is another metric that helps us not to impact user experience with the image load time changes. Some of the optimisation work can affect the user’ interaction with the page and TTI measures when the page is fully available for user input.

We are continuously identifying ways to improve the performance of our pages to give our users the best Cazoo experience possible from the start of their browsing journey to the delivery of their car.

--

--