DEV Community

Cover image for Understanding Next/Image
Yann Gouffon
Yann Gouffon

Posted on • Updated on

Understanding Next/Image

With Next.js version 10, a new image component was introduced to offer modern format and on-demand optimisation for images as well. If you came from Gatsby, it's the Next.js answer to gastby-image and it just rocks!

Images are always rendered in such a way as to avoid Cumulative Layout Shift, a Core Web Vital that Google is going to use in search ranking.

Weirdly, it's so simple and magic that I was struggling to know how to use it. Also, the doc is not great to really understand how it works and to advise you to the most common practice: responsive user interface.

Let's dive in

If you read the short documentation page about next/image , the only example you will see is basically this one.

<Image
  src="/my-16-by-9-big-image.jpg"
  alt="Picture of something nice"
  width={1000}
  height={1000}
/>
Enter fullscreen mode Exit fullscreen mode

It's an easy mistake to think that our output will be a 1000 by 1000 pixels image (and a 2x for retina), but instead we've got a 1080 ร— 608 pixels image stretched in a square... So before going further, we need to understand few concepts about this component.

The layouts

There is four different layout available for your <Image /> :

  • layout="intrinsic" is the default value; it's basically a CSS max-width. In our example, the image will be 1000 pixels wide on desktop and will fit to its parent width on mobile, but the resolution will not change, only the displayed size.
  • layout="fixed" is pretty self-explanatory; just like a CSS width, the image will be displayed in the defined sizes without any resizing. Here 1000 by 1000 pixels, but the resolution is still 1080 ร— 608 pixels.
  • layout="responsive" is the magic and maybe the main one to remember, because we are in 2021 and performances matter. This time it's more like a CSS width: 100%;, but unlike the first two above, it will provide a large number of different resolutions in the srcset output.
  • layout="fill" is useful when you don't want (and don't need) to define a width and a height. It's a standard CSS object-fit. For this variant only, you will be able to add the extra objectFit and objectPosition properties to your component; they work just like the related CSS specification. It also provides a responsive srcset.

What you must remember:

  • The width and height properties must match your image ratio, unless you are using layout="fill"
  • intrinsic (by default) and fixed are used for static resolutions and responsive and fill for responsive resolutions.
  • If you know the image size, use responsive and if you don't, use fill

The resolutions

As you can see in our example, the resolution doesn't quite match the size. It's because there are two *options in your next.config.js that you must be aware of:

  • deviceSizes are large breakpoints
  • imageSizes are small breakpoints

By default, these options are set this way:

module.exports = {
  images: {
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
}
Enter fullscreen mode Exit fullscreen mode

These two arrays are merged to form a complete collection of potential widths. So, if like me, you want a picture resized precisely to 1000 by 1000 px (and 2000 for retina), these sizes must be present in the deviceSizes array.

*There are also other options to allow external images or to define a custom loader.

Other available props

Apart from the main things to know when using next/image, there are some useful properties to be aware of:

  • loader is useful to pass a loader component
  • sizes is to override the default sizes of 100vw, useful only when layout="responsive" or layout="fill" are defined
  • quality can be used to override the default quality of 75
  • priority must be used only when the image is visible above the fold. It's false by default.
  • loading is lazy by default, but can be changed to eager to force an immediate loading.
  • unoptimized if you want something close to the default <img /> behaviour.
  • You can also use style, srcSet and decoding to directly target the <img />

Examples

Now that we better understand how next/image works and how it can be configured, here is some real-life examples.

Classic responsive

Example of a responsive image inside a blog post content.

<Image
  src="/my-16-by-9-big-image.jpg"
  alt="Picture of something nice"
  width={800}
  height={450}
  layout="responsive"
  quality={65}
/>
{/* Or for the same result */}
<Image
  src="/my-16-by-9-big-image.jpg"
  alt="Picture of something nice"
  width={16}
  height={9}
  layout="responsive"
  quality={65}
/>
Enter fullscreen mode Exit fullscreen mode

Automatic responsive

As we quickly saw earlier, the size property is 100vw by default. If you want a perfect match to your image size, you can use something like react-cool-dimensions and wrap the <Image /> into a new component.

import React from 'react';
import useDimensions from 'react-cool-dimensions';
import Image from 'next/image';

export default (props): JSX.Element => {
  const { observe, width } = useDimensions<HTMLDivElement | null>();

  return (
    <div ref={observe}>
      <Image
        {...props}
        layout="responsive"
        quality={65}
        sizes={width !== undefined ? `${Math.round(width)}px` : '100vw'}
      />
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Unknown/variable size with fixed ratio

Sometimes pictures came from an outside source (CMS, APIs, etc) and the image size (width, height) is not available or the ratio can vary. For this case, the layout="fill" is very useful with something like @tailwindcss/aspect-ratio.

<div className="aspect-w-16 aspect-h-9">
  <Image
    src="/my-big-variable-image.jpg"
    alt="Picture of something nice"
    layout="fill"
    objectFit="cover"
  />
</div>
Enter fullscreen mode Exit fullscreen mode

Unknown/variable size with variable ratio

Sadly for the moment, there is no way to respect an image ratio without knowing its width and height or at least, its ratio. You can still define an area where the image will be rendered without crop. For example, here, inside a gray square.

<div className="aspect-w-1 aspect-h-1 bg-gray-100">
  <Image
    src="/my-big-variable-image.jpg"
    alt="Picture of something nice"
    layout="fill"
    objectFit="contain"
  />
</div>
Enter fullscreen mode Exit fullscreen mode

Conclusion

next/image is a great add to the Next.js ecosystem, especially for people coming from Gatsby. It provides a very simple way to add the responsive layers to your images without any complicated backend configuration. It's another great example of the capabilities of clients to manage the media from a frontend perspective. Let your backend deal with the sources images and let your client application deal with the size needed by the consumers.

Top comments (9)

Collapse
 
titungdup profile image
dhondup

How to serve high quality image for retina display like 2x, 3x images? Usually we provide multiple images with different resolutions and serve that according to device dpi using srcset but in Next Image we only provide one src for an image. So from where does Next find high res image for different dpi screens?

Collapse
 
northbeststudio profile image
Rob

Helpful post. Do you know why Next Image cannot deal with variable size and variable ratio images?

This seems like an essential use case. Any CMS will usually generate different size and ratio images. Shame that they cannot take advantage of Next's image component.

Collapse
 
mrtanguero profile image
Ivan Jovanovic • Edited

Is this what you were looking for, Rob?
dev.to/felixhaeberle/responsive-fi...

Collapse
 
iainfreestone profile image
Iain Freestone

Great post, Thank you

Collapse
 
yago profile image
Yann Gouffon

Appreciated!

Collapse
 
jonm01 profile image
Jon Mathew

with the above fix backdrop-filter: blur(5px); stopped working on a div that overlaps with the image on chrome and firefox but works fine on Safari

Collapse
 
daveteu profile image
Dave

Can show your deviceSizes and ImageSizes array? I dont understand why 2 different arrays and how it works.

Collapse
 
khaled311 profile image
Khaled Sarhan

Thanks a lot Yann โ™ฅ

Collapse
 
andberry profile image
Andrea Berardi

Great post, thank you so much!