Start using AVIF in your Next.js project

Introduction

Next.js Image Optimization is easy! The blog you're reading uses both the latest version of React and Next.js.

You must make sure that

1next.config.js
includes the following:

1module.exports = {
2 images: {
3  formats: ['image/avif', 'image/webp']
4 }
5}

Next.js will handle all the hard work behind the scenes for you. The team behind Next.js has been working to improve image processing since version 10 and AVIF is supported since version 12. They offer both an integrated

1<Image>
component (
1next/image
) and a built-in Image Optimization API. They describe their image component as an extension of the HTML img element designed for the modern web. Images in this component are resized, optimized and automatically served in the correct format based on the visitor's device and browser. For example, you would not deliver a high-resolution image to a mobile device. Furthermore, the images support the Core Web Vitals by not shifting their layouts while lazy-loading images. Furthermore, this service can also be used if the server that contains the images of the website is a CDN and not a server hosted by the website.

See the Next.js Documentationfor more information.

Next.js image component

To use the Next.js image component, you add the image file to your project directory or use an external source and pass it as a

1src
prop to the Next.js image component, which you have imported on top of the file. It will convert images to both WebP and AVIF depending on the browser support of your visitors. Please note that to this date, images loaded via CSS will not be optimized, although we hope that this will be the case in future versions.

1import Image from 'next/image'
2(..)
3 <Image
4  src="/yourmum.jpg"
5  alt="Picture of your mum"
6  width={9001}
7  height={500}
8 />
9(..)

CSS Images

Until this point, if you rely heavily on CSS images, you can use the third-party plugin with Next.js called next-optimized-images. It has many additional features, and it ** supports loading images with CSS**, which is useful. However, the plugin does not support AVIF and opts for WebP. Even though the author released news on a new version following a canary branch with promised AVIF support, the development has not been continued as of August 2020.

How do we at avif.io deal with AVIF support?

As we don't want to rely on Vercel or third-party components, we perform the following steps.

1. Add browser support detection script

To find out if you as a visitor have a browser with AVIF support, we have implemented the following 600-byte script in our header:

1function F(a){document.documentElement.classList.add(a)}var A=new Image;A.src="data:image/avif;base64,AAAAFGZ0eXBhdmlmAAAAAG1pZjEAAACgbWV0YQAAAAAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAC8AAAAGwAAACNpaW5mAAAAAAABAAAAFWluZmUCAAAAAAEAAGF2MDEAAAAARWlwcnAAAAAoaXBjbwAAABRpc3BlAAAAAAAAAAQAAAAEAAAADGF2MUOBAAAAAAAAFWlwbWEAAAAAAAAAAQABAgECAAAAI21kYXQSAAoIP8R8hAQ0BUAyDWeeUy0JG+QAACANEkA=",A.onload=function(){F("avif")},A.onerror=function(){var a=new Image;a.src="data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",a.onload=function(){F("webp")}};

2. Create image component with modern markup

We have developed our own image component (visit Github for the latest version), which uses all the features that modern image markup should take into account, from the lazy load to the aspect ratio. We have to choose a path and an alt text. For more information on the perfect image markup visit Guide to Image Performance.

3. Convert images with sharp on build time

Finally, we have the NodeJS library sharpintegrated into our build and release script to convert images before we upload our website data to Firebase. The sharp script detects all images in a specific folder and converts them into all the different formats and sizes we need. Below is the current script we are using.

1const sharp = require("sharp");
2const fs = require("fs");
3const path = require("path");
4const output = "../public/img/";
5const input = "../images/";
6const jpgQuality = { mozjpeg: true, quality: 50, progressive: true };
7const webpQuality = { quality: 50, reductionEffort: 6 };
8const avifQuality = { quality: 45, speed: 1 };
9const sizes = [1440, 720, 360];
10fs.readdir(input, (err, files) => {
11 console.log("Found " + files.length + " files. Converting now, please be patient..");
12 files.forEach((file) => {
13  function convert(size) {
14   let fileShort = path.parse(file).name;
15   sharp(input + file)
16    .jpeg(jpgQuality)
17    .resize({ width: size })
18    .toFile(output + fileShort + "-" + size + ".jpg");
19   sharp(input + file)
20    .webp(webpQuality)
21    .resize({ width: size })
22    .toFile(output + fileShort + "-" + size + ".webp");
23   sharp(input + file)
24    .avif(avifQuality)
25    .resize({ width: size })
26    .toFile(output + fileShort + "-" + size + ".avif");
27  }
28  if (file.endsWith(".png") || file.endsWith(".jpg") || file.endsWith(".jpeg")) {
29   for (let i = 0; i < sizes.length; i++) {
30    convert(sizes[i]);
31   }
32  }
33 });
34});
35

Keep in mind that this is suitable for website without many images, as it significantly increases build time. A way to bypass that could be creating an own sharp API and using Incremental Static Regeneration.

We use cookies for our services.
OK