Best CLS Practices for Images
Tags: webdev, performance, webvitals, tutorial
Published: 2021-05-07 08:29:39

As Google moves closer to its June target for introducing Core Web Vital metrics into its algorithm, I thought it would be great to start helping the community get to grips with what to expect. 

There are 3 Core Web Vitals: [LCP](https://web.dev/lcp/) (Largest Contentful Paint), [CLS](https://web.dev/cls/) (Cumulative Layout Shift), and [FID](https://web.dev/fid/) (First Input Delay). I plan to go over each in more detail, however, I thought I would start with images as it's easy to consume and implement. 

First, let's chat about what CLS actually is. According to Google: 

> CLS measures the sum total of all individual layout shift scores for every unexpected layout shift that occurs during the entire lifespan of the page.

A layout shift occurs when an element on the page moves its position during frame render and can have significant impacts on user experience. Its often seen on some websites where content jumps during or after page load.

One of the biggest culprits of layouts shifts is images. 
As I'm sure most of you reading this article will know, before responsive web design patterns came along, it was always a best practice to add `width` and `height` dimensions to images.

Following the responsive web, we were advised to remove static `width` and `height` attributes and rather focus on handling images more fluidly:

```
img {
  height: auto;
  max-width: 100%;
}
```

The rule above has been used countless times to ensure that images respond gracefully to changing `window` sizes or device dimensions. 

With the introduction of CLS, we have now been advised to handle images slightly differently in order to allow for faster rendering with minimal layout shift/repositioning. 

Here are some guidelines to ensure that your CLS stays closer to 0 when running a Lighthouse audit:

### 1. Ensure all images have width and height attributes

```
<img src="https://source.unsplash.com/1600x900/?nature" width="1600" height="900" alt="Waterfall" />
```
What the browser does with these attributes is calculate the aspect-ratio along with its responsive CSS rule cousin:

```
img {
 aspect-ratio: attr(width) / attr(height);
 height: auto;
 max-width: 100%;
}
```

The above allows the browser to understand how the image will be placed on the page and what space will be needed to be reserved in order to do so. There's no need for you to add the aspect-ratio property to your CSS as the browser stylesheet now handles this for us. 

### 2. Handle width and height with responsive image techniques.

If you have responsive images using `srcset` or `<picture>` calculate the aspect ratio of the image and add the aspect-ratio as `width` and `height` attributes.

```
<img srcset="large.jpg  1024w, medium.jpg 640w, small.jpg 320w" sizes="(min-width: 36em) 33.3vw, 100vw" src="small.jpg"
alt="A rad wolf" width="16" height="9" />
```
This will help the browser understand the aspect-ratio, pass Lighthouse audits and still use responsive sizes to handle images at different breakpoints

### 3. Ensure all images are LazyLoaded.

There are multiple techniques to handle this but using the lazy="loaded" attribute can help in [modern browsers](https://caniuse.com/?search=lazy).

```
<img src="https://source.unsplash.com/1600x900/?nature" width="1600" height="900" alt="Waterfall" loading="lazy" />
```

You can also use this [really great library](https://github.com/aFarkas/lazysizes) for handling the loading of images in a holistic and well-supported way or you can look at manually implementing the [LQIP](https://medium.com/@imgix/lqip-your-images-for-fast-loading-2523d9ee4a62) technique.

### 4. Preload images above-the-fold

Another really useful technique is to preload images that are placed above-the-fold. Preload has [relatively okay support] (https://caniuse.com/?search=preload) across the web, but you will need a [fallback for IE11](https://dev.to/kengste/how-to-maximise-browser-compatibility-for-link-rel-preload-3h4).

```
<link rel="preload" as="image" href="/path/to/image" />
```
This allows browsers to cache and request the image at a much higher priority, therefore arriving in the browser far sooner.

You can also specify a type attribute, which would allow you to be more accurate with regards to the resource you want to preload:

```
<link rel="preload" as="image" href="/path/to/image" type="image/webp" />
```

### 5. Ensure that you're serving images in modern formats

This can be a little hard to manage, however, some CDN's provide useful query strings that set images in certain formats on the fly. WebP is probably the most common but there are other formats like AVIF that can provide even further optimization. There's a great [comparison chart](https://cloudinary.com/blog/time_for_next_gen_codecs_to_dethrone_jpeg) over at Cloudinary if you want to take a look.

Some other minor tips and tricks also include:

1. Serving images over a CDN
2. Ensuring that images are cached appropriately on the server
3. Ensuring that images are correctly sized, in other words, you're not rendering a 3000x1500 image in a 300x150 slot. 

I hope this helps, feel free to get in [touch with me over email](mailto:hello@dainemawer.com) if you have any questions, I do offer free consulting slots!