Skip to content

Fix Layout Shifts with Image Component

I’m sure you’ve experienced one of those moments where you visit a page on a website, maybe by clicking on a blog post. While you were still on the page, some additional page content (images, ads e.t.c) got loaded, and suddenly, you couldn’t find your position again. Layout shifts occur when an existing content on a page moves from its initial position because something new was introduced to the page. See here for more on cumulative layout shift.

There are several reasons why these unexpected movements happen, but this article will focus on preventing image-based layout shifts with the Next.js Image component.

Here is a link to the demo on CodeSandbox.

Images are one of the major causes of layout shift, and one way to avoid this is to specify the width and height attributes on the <img> tag. This way, the browser knows how much space to reserve for the image if it takes a while to download.

<img src="/sunset1.jpg" alt="Sunset" width={600} height={450} />
Code language: HTML, XML (xml)

Specifying the width and height on images also has issues when attempting to use CSS to ensure the image dimensions don’t overflow their allotted space. However, we are not going to cover that in this article. You can find more information on that in this post.

The Next.js Image component serves the HTML img tag under the hood, but it is packed with a lot of performance optimizations that help improve the Core Web Vitals for applications built with Next.js.

The width and height properties are required when using the Image component, and there are three ways to add them to the Image component.

When you import your local image statically, you don’t need to set the width and height properties on them.

import Image from "next/image";

// import your local image from the public folder
import picture from "../public/picture.jpeg";

export default function Home() {
  return (
    <div style={{ display: "flex" }}>
      <div style={{ width: "400px", margin: "auto" }}>
        <h1>My Homepage</h1>
        <Image
          src={picture}
          alt="My Picture"
          // width={500} automatically provided
          // height={500} automatically provided
        />
        <p>
          Contrary to popular belief, Lorem Ipsum is not simply random text. It
          has roots in a piece of classical Latin literature from 45 BC, making
          it over 2000 years old. Richard McClintock, a Latin professor at
          Hampden-Sydney College in Virginia, looked up one of the more obscure
          Latin words, consectetur, from a Lorem Ipsum passage, and going
          through the cites of the word in classical literature, discovered the
        </p>
      </div>
    </div>
  );
}
Code language: JavaScript (javascript)

First, we imported the Image component at the top of the file, and then we imported a static image file. Setting the width and height properties on an image is important in preventing layout shifts and ensuring that the image tag creates a holding space for the referenced image, but Next.js takes care of that if the image was imported statically.

Based on the imported image file, Next.js automatically determines the width and height to set on the Image component.

For remote images, you need to provide the width and height properties manually as you would when using the native HTML tag.

<Image src="/picture.jpg" alt="My Picture" width={300} height={500} />
Code language: HTML, XML (xml)

In the snippet above, we provided a partial URL for a remote image optimized and served from Cloudinary. We explicitly defined the width and height properties because, at build time, Next.js won’t have access to the remote image. See here for more information on working with remote images.

The Next.js Image component also accepts an optional layout property with different modes for determining its size on a page. The default layout behavior for the Image component is intrinsic. This scales images down for smaller viewports and maintains their original size for larger viewports.

If you don’t know the sizes of the images you are working with, one option is to use the fill layout mode.

<div
  style={{
    width: "300px",
    height: "500px",
    position: "relative",
    alignSelf: "center",
  }}
>
  <Image
    src="https://res.cloudinary.com/ifeomaimoh/image/upload/v1637573164/picture.jpg"
    alt="My Picture"
    layout="fill"
  />
</div>
Code language: HTML, XML (xml)

In the snippet above, we have an Image component whose src property contains a URL string of a remote image on Cloudinary. With the fill layout mode, the image will stretch to its parent element’s size, so we don’t need to specify the width and height properties. The parent element must have a declared position whose value is relative in its stylesheet. See here for more on image layout modes.

See here for guidelines on styling the Next.js Image component.

We’ve seen the three ways we can achieve visual stability and prevent layout shifts by using the Image component when building Next.js applications. The Next.js Image component offers a lot of optimization benefits. See this page for more advanced use cases.

Useful Links

Back to top

Featured Post