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}
/>
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 CSSmax-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 CSSwidth
, 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 CSSwidth: 100%;
, but unlike the first two above, it will provide a large number of different resolutions in thesrcset
output. -
layout="fill"
is useful when you don't want (and don't need) to define awidth
and aheight
. It's a standard CSSobject-fit
. For this variant only, you will be able to add the extraobjectFit
andobjectPosition
properties to your component; they work just like the related CSS specification. It also provides a responsivesrcset
.
What you must remember:
- The
width
andheight
properties must match your image ratio, unless you are usinglayout="fill"
-
intrinsic
(by default) andfixed
are used for static resolutions andresponsive
andfill
for responsive resolutions. - If you know the image size, use
responsive
and if you don't, usefill
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],
},
}
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 of100vw
, useful only whenlayout="responsive"
orlayout="fill"
are defined -
quality
can be used to override the default quality of75
-
priority
must be used only when the image is visible above the fold. It'sfalse
by default. -
loading
islazy
by default, but can be changed toeager
to force an immediate loading. -
unoptimized
if you want something close to the default<img />
behaviour. - You can also use
style
,srcSet
anddecoding
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}
/>
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>
);
};
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>
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>
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)
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?
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.
Is this what you were looking for, Rob?
dev.to/felixhaeberle/responsive-fi...
Great post, Thank you
Appreciated!
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
Can show your deviceSizes and ImageSizes array? I dont understand why 2 different arrays and how it works.
Thanks a lot Yann ♥
Great post, thank you so much!