Module 3: Performance
Images

According to Web Almanac (opens in a new tab), images account for a huge portion of the typical website’s page weight (opens in a new tab) and can have a sizable impact on your website's LCP performance (opens in a new tab).

The Next.js Image component extends the HTML <img> element with features for automatic image optimization:

  • Size Optimization: Automatically serve correctly sized images for each device, using modern image formats like WebP and AVIF.
  • Visual Stability: Prevent layout shift (opens in a new tab) automatically when images are loading.
  • Faster Page Loads: Images are only loaded when they enter the viewport using native browser lazy loading, with optional blur-up placeholders.
  • Asset Flexibility: On-demand image resizing, even for images stored on remote servers

Usage and Props

import Image from "next/image";

Here's a summary of the props available for the Image Component:

Next.js

Required Props

The Image Component requires the following properties: src, width, height, and alt.

import Image from "next/image";
 
export default function Page() {
  return (
    <div>
      <Image
        src="/profile.png"
        width={500}
        height={500}
        alt="Picture of the author"
      />
    </div>
  );
}

Remote images

To safely allow optimizing images, define a list of supported URL patterns in next.config.js. Be as specific as possible to prevent malicious usage.

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "s3.amazonaws.com",
        port: "",
        pathname: "/my-bucket/**",
      },
    ],
  },
};

You should add the priority property to the image that will be the Largest Contentful Paint (opens in a new tab) (LCP) element for each page. Doing so allows Next.js to specially prioritize the image for loading (e.g. through preload tags or priority hints), leading to a meaningful boost in LCP.

The LCP element is typically the largest image or text block visible within the viewport of the page. When you run next dev, you'll see a console warning if the LCP element is an <Image> without the priority property.

Once you've identified the LCP image, you can add the property like this:

import Image from "next/image";
import profilePic from "../public/me.png";
 
export default function Page() {
  return <Image src={profilePic} alt="Picture of the author" priority />;
}

See more about priority in the next/image component documentation (opens in a new tab).

Image Sizing

One of the ways that images most commonly hurt performance is through layout shift, where the image pushes other elements around on the page as it loads in. This performance problem is so annoying to users that it has its own Core Web Vital, called Cumulative Layout Shift (opens in a new tab). The way to avoid image-based layout shifts is to always size your images (opens in a new tab). This allows the browser to reserve precisely enough space for the image before it loads.

Because next/image is designed to guarantee good performance results, it cannot be used in a way that will contribute to layout shift, and must be sized in one of three ways:

  1. Automatically, using a static import (opens in a new tab)
  2. Explicitly, by including a width and height property
  3. Implicitly, by using fill (opens in a new tab) which causes the image to expand to fill its parent element.

As a bonus tip, I always add extra sizing to my images :

<Image
  src={event.cover_url}
  alt={event.cover_alt}
  layout="responsive"
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 50vw"
  width={500}
  height={500}
/>

In the next/image component, the sizes attribute instructs the browser on how to select the most appropriate image size based on the given media conditions (viewport size).

For the provided code:

  1. If the viewport width is up to 768px, the image will take up 100% of the viewport width (100vw).
  2. If the viewport width is between 768px and 1200px, the image will take up 75% of the viewport width (75vw).
  3. For viewports wider than 1200px, the image will take up 50% of the viewport width (50vw).

The browser uses this sizes information, along with the actual image sizes available (from the srcset attribute, if provided), to download the most appropriate image size for the user's device and viewport conditions.

Exercise:

Apply what you learned above and use next/image while making sure to serve reduced size images!



Resources: