Preventing CLS with Dynamic Images

Brad PrestonBrad Preston
3 min read

When adding images to our websites, it’s crucial to prevent the layout from shifting while the image loads. Cumulative Layout Shift (CLS) can be described as unexpected movement while the page content is loading. For example, you go to click on a button, but an ad loads in, moves the button below the cursor and you end up clicking on the ad instead. So frustrating!

A major contributor to CLS issues are images. If an image loads without having space allocated for it, then the image will cause the content around it to shift once it finally loads in. Let’s see how we can allocate the space for images to prevent CLS.

Width and Height

If you happen to know the width and height of the image beforehand, then you can set the width and height attributes on the <img> tag.

<img src="image.png" width="1280" height="720">

The width and height attributes will not affect responsiveness and will not force the image to be explicitly this size. However, using the width and height attributes will allow the browser to determine the image’s aspect ratio and use that aspect ratio to allocate the space in it’s container. For example, if you have a product card that is 300 pixels wide, the image above will take up a 16:9 aspect ratio at 300 pixels wide.

If you don’t know the exact width and height of your image, but you know it’s aspect ratio, then you can set the width and height of the image to an aspect ratio that matches your image.

Unknown Image Size

What happens if the image has an unknown dimension? Maybe you’re getting the image from an API and the image size isn’t clear based on the documentation.

In situations like this, you’ll have to manually allocate space for the image. It’s best to allocate the space dynamically using an aspect ratio CSS property.

<div class="card">
    <img src="image.png" class="card-image">
</div>

<style>
.card {
    width: 300px;
}
.card-image {
    width: 100%;
    height: auto;
    aspect-ratio: 16/9;
    object-fit: cover;
}
</style>

Here, we create a card with a width of 300px (I know this card isn’t technically responsive, but bare with me for this example). Since we don’t know the actual size of the image, we allocate a 16:9 aspect ratio that takes up 100% of the card’s width. Then we set the image to cover the entire 16:9 space. If you prefer the image to be contained to the height of the space even if that means some horizontal space around the image, then you can replace cover with contain.

Now, while the images are loading in, even if we don’t know the size of the images, the layout will not shift around once the images load. You’ll replace the aspect ratio with whatever your card needs. Maybe it needs to be a 3:4 vertical rectangle or a 1:1 square. Whatever it is, this will allocate the space within the card before the images actually load, thus preventing the layout shift.

0
Subscribe to my newsletter

Read articles from Brad Preston directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Brad Preston
Brad Preston

I'm a software developer with a background in Golang and JS/TS