Image Optimization with NextJS
jideabdqudus
Posted on May 6, 2022
NextJS is fast becoming my favorite frontend framework because of the endless advantages over a basic React application, one of those said benefits would be the Built-in Image Component.
In this article, we would take a look at the Image component from NextJS and learn how to use it to optimize an image in our web app.
By the end of this article, you should understand the following concepts:
- Image Optimization
- Using
next/image
- Image Props
- Configuring
next.config.js
- Usage of the native
< img >
tag in NextJS
Image Optimization
Ordinarily, if you were going to make use of an image in your website/app you would do this ( assuming the image is in the same directory as the webpage it is accessing ):
<img src="./apple.jpg">
You can go further by adding an alternative text (for screen readers or when the image cannot be loaded) by doing this:
<img src="./apple.jpg" alt="Image of an apple"/>
However, this format doesn't solve image optimization aspects like image size, web formats, and responsiveness with this single usage.
NextJS offers automatic image optimization which solves all of the above as well as common tasks like internalization and routing.
The golden rule for any performance optimization simply put is giving users what they want in the shortest possible time or providing a fall-back if need be.
Hence NextJS provides us with a built-in image optimization API, next/image
, a canonical form for native automatic image optimization.
Using next/image
The Image component in NextJS is quite similar to the native html <img>
, it's an extension of this element and can be used by importing it from next/image
and using it like you'd use a component with props.
import Image from 'next/image';
export default function SampleImage({source}) {
return (
<div>
<Image src={source} alt='Image alt text'/>
</div>
)
}
The Image tag has a couple of props available to it for use asides the src and alt prop, we'd take a look at some of them
width
and height
prop
The width and height of the image is in pixels , when adding the width and height be sure to add the correct dimension. If a different aspect ratio is added, the image would adjust accordingly. For example if the width and height of a (1400 x 700) image gets changed to (400 x400) as shown below, it could result in a skewed image.
import Image from 'next/image';
export default function SampleImage({source}) {
return (
<div>
<Image
src={source}
alt='Image alt text'
height={400}
width={400}
/>
</div>
)
}
layout
prop
There may be times you do not know the width and height of an image, but still want it to fill the entire space while keeping its aspect ratio. In this situation, you can leave out the width and height prop on the Image component. Instead, add a prop of layout="fill"
. This will stretch the image to the width and the height of the parent element. When using the layout="fill"
prop, it is often best to pair it with objectFit="cover"
. This will allow the image to maintain its aspect ratio while filling the element’s entire content box.
To achieve this, wrap the Image component as a child of a <div>
element. Then add a width and height to the parent <div>
element, along with giving it a position="relative"
.
import Image from 'next/image';
export default function SampleImage({source}) {
const myStyle = {
height: '400px',
width: '400px',
position: 'relative'
}
return (
<div style={myStyle}>
<Image
src={source}
alt='Image alt text'
layout='fill'
objectFit='cover'
/>
</div>
)
}
This way, we can see that the image is taking up the 400-pixel square that we wanted, but the aspect ratio of the image is still in place. The parts of the image that do not fit within the parent element are clipped.
Other layout
values are intrinsic, fixed, and responsive.
loader
prop
A loader is a function returning a URL string for the image, given the following parameters (src
, width
, quality
). Setting the loader as a prop on the Image component overrides the default loader defined in the images section of next.config.js
.
import Image from 'next/image'
const sampleLoader = ({ src, width, quality }) => {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
const MyImage = (props) => {
return (
<Image
loader={sampleLoader}
src="me.png"
alt="My Picture"
width={500}
height={500}
/>
)
}
sizes
prop
You can specify a list of image widths using the images.imageSizes
property in your next.config.js
file. These widths are concatenated with the array of device sizes to form the full array of sizes used to generate image srcsets.
module.exports = {
images: {
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
}
Or by defining it in your component like,
<Image
src={src}
alt="image-alt-text"
sizes="320 640 700"
layout="responsive"
/>
Keep in mind that it is recommended to define sizes
only when using a responsive
or fill
layout.
quality
prop
The quality of the optimized image, is an integer between 1
and 100
where 100
is the best quality. Defaults to 75
.
<Image
src={src}
alt="image-alt-text"
quality={100}
layout="fill"
/>
priority
prop
By default, images are not prioritized (because they are lazy-loaded), meaning priority defaults to false
. When true
, the image is considered high-priority and preloaded.
You should use the priority
property on any image detected as the Largest Contentful Paint (LCP) element.
Should only be used when the image is visible above the fold. Defaults to false
.
<Image
src={src}
alt="image-alt-text"
width={500}
height={300}
priority
/>
placeholder
prop
This placeholder
property is used as a fallback image when an image is loading. Its possible values are blur
or empty
.
When empty
, there will be no placeholder while the image is loading, only empty space. When blur
, the blurDataURL
property will be used as the placeholder. If src
is an object from a static import and the imported image is .jpg, .png, .webp, or .avif, then blurDataURL will be automatically populated.
<Image
src={src}
alt="image-alt-text"
width={500}
height={300}
placeholder="blur"
/>
blurDataURL
prop
The blurDataURL
prop is a placeholder image that loads before the src image successfully loads and must be a base64-encoded data URL image that is effectual only when used in combination with placeholder=“blur”
.
<Image
src={src}
alt="image-alt-text"
width={600}
height={450}
placeholder="blur"
blurDataURL=”data:image/png;base64,[IMAGE_CODE_FROM_PNG_PIXEL]”
/>
objectFit
prop
The objectFit
prop defines how the image will fit into the container of it's parent, quite similar to the object-fit CSS property. It is used with layout=fill
or an image with a set width
and height
.
<Image
src={src}
alt="image-alt-text"
layout="fill"
objectFit="contain"
/>
It has a possible value of: contain
, cover
, fill
, none
, and scale-down
.
unoptimized
prop
When true
, the source image will be served as-is instead of changing quality, size, or format. Defaults to false
.
<Image
src={src}
alt="image-alt-text"
width={700}
height={450}
unoptimized
/>
Configuring next.config.js
You can configure your NextJS image through the next.config.js
file
domains
When using an external URL to load images, you must add it to domains
in next.config.js
module.exports = {
images: {
domains: ['example.com'],
}
}
loader
By default, NextJS handles image optimization but you can hand that responsibility over to a cloud provider such as Cloudinary or imgix that is more dedicated to images than just general optimization.
module.exports = {
images: {
loader: 'cloudinary',
path: 'https://your-site.com/assets/images/'
}
}
Keep in mind that when loader
is set to an external image service, the domains
config is ignored.
For more advanced cases of props in NextJS, there are other props that you can add to the Image component as well as configurations. Check out the full documentation here.
Conclusion
Image optimization in Next.js improves the user and developer experience but just like every other thing in programming, the Image component has some limitations one of which is its inability to adjust CSS directly. Unlike the native <img>
element whereby you can pass a style
prop to override its CSS. The NextJS image component doesn't support the style
property at all. Hence to style the source image, name it with a className
then target it with your CSS.
<Image
src={src}
alt="image-alt-text"
width={700}
height={450}
className="myImage"
/>
P.S: Next.js forces using their component instead of the native <img>
tag by including the corresponding linter check to the app build process. So if you're going to make use of the <img>
tag in a NextJS application you'd add the following to disable the check
// eslint-disable-next-line @next/next/no-img-element
<img
src={src}
alt='myImg'
className='myImage'
/>
Or by adding "@next/next/no-img-element": "off"
in the .eslintrcconfig
file.
I hope you enjoyed reading this as much as I enjoyed writing it and would be building your NextJS app as soon as possible.
Resources used:
Posted on May 6, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 30, 2024