How To Improve Lighthouse Scores by Avoiding <img> Layout Shifts
Tags: webdev, performance, css, design
Published: 2023-02-23 18:04:39

One of the most common killers of Lighthouse scores, and also one of the easiest to solve, would have to be setting the correct aspect ratio on your images. Layout shifts can happen for many reasons, but here we’ll focus on how images can have a negative effect.

![Example of image loading changes the content layout](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8qojtss063cz81vbjogr.gif)

Basically, it’s annoying to be reading content only to see the layout adjust and that same content moved to another location. This is why [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/) and other performance measuring tools have a metric called [Cumulative Layout Shift](https://web.dev/cls/), or CLS.

It’s pretty straightforward: if your page has CLS issues, your Lighthouse scores go down.

![screenshot of Lighthouse CLS showing the main image of the document.](https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fdfbbcb1d13154507a7e0ff9eea9bd8f1?width=705)

![screenshot of Lighthouse CLS timeline.](https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F0915ea4931654f6c84b8f2b796692879?width=705)

Another challenge is that we’re also designing pages that are responsive. Meaning that the same content should look good on both desktop and mobile, so setting exact dimensions for images is usually not an option.

Luckily, there are two recommended cross-browser approaches to solving image CLS issues:

- `aspect-ratio` CSS property on `img` selector
- `width` and `height` attributes in the `img` tag, with `height: auto` CSS

## Aspect Ratio CSS

The [aspect-ratio](https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio) CSS property, as you guessed it, sets the aspect ratio of an element. This means it determines the ratio between the width and height, rather than specifying an image’s exact dimensions.

```css
img {
  aspect-ratio: 16/9;
  width: 100%;
}
```

Here we’re assigning CSS to the `img` element and using an aspect ratio of 16 units by 9 units.

What’s cool is that even before loading the image, the browser can now reserve space for it. This means that the layout and content of the page will not shift after the image loads.

Depending on your design, it also might be worthwhile to set a background color to the `img` element so users are given a hint that the image hasn’t loaded yet.

```css
img {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: gray;
}
```

![Example of layout content not shifting after the image loads](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23h55kk7ei7jw5xdt1qq.gif)

In the screen recording above, you’ll notice that there’s initially a gray square in place of the image, which acts as an image placeholder so the content stays in the same place even after the image loads.

### object-fit: cover

Another recommendation is to also add the `object-fit: cover` CSS:

```css
img {
  aspect-ratio: 16/9;
  width: 100%;
  object-fit: cover;
  background-color: gray;
}
```

The [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) property tells the browser what to do if the aspect ratio is off. So instead of forcing a poorly stretched image because the ratio is wrong, the image can instead keep its own aspect ratio, and still fit nicely within the given area.

## Width and Height Attributes with Height Auto CSS

Another approach that’s worth trying for your use case is to set the `width` and `height` attribute of the `img` element, and also the `height` CSS property to `auto`.

```html
<img width="1200" height="675" src="…" alt="…" />
```

```css
img {
  height: auto;
}
```

Similar to the aspect ratio CSS approach, the browser now knows how to calculate how much space the image will take up before it loads.

## Improve those Lighthouse scores

Which approach you use is up to you, but regardless, if you want an easy way to improve your Lighthouse scores, then ensuring the aspect ratio of your images is a quick win.

## About me

Hi! I’m [Adam](https://twitter.com/adamdbradley), Director of Technology at [Builder.io](https://www.builder.io/).

We make a way to drag + drop with your components to create pages and other CMS content on your site or app, [visually](https://www.builder.io/blog/headless-cms-workflow).
So this:
```tsx
import { BuilderComponent, registerComponent } from ‘@builder.io/react’
import { Hero, Products } from ‘./my-components’
// Dynamically render compositions of your components
export function MyPage({ json }) {
  return <BuilderComponent content={json} />
}
// Use your components in the drag and drop editor
registerComponent(Hero)
registerComponent(Products)
```
Gives you this:
![Gif of Builder.io](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/au5t8ti43cci5n6t6cfb.gif)

{% twitter 1627708760293605384 %}