How to present a blurred version of an image in NextJS as it's being downloaded?

Viewed 12341

I'm looking for a similar effect as this one below:

blur image effect

I have done something similar with Gatsby, but I'm wondering if this is possible to do with NextJS?

4 Answers

You can do it without using an external library with not much code.

https://codepen.io/darajava/pen/GRZzpbB?editors=0110

I added animations in there too on load. The image will fit to the width of its parent container. Usage is simple:

<LoadImage largeImageSrc={url} smallImageSrc={url} />

For version above 10.2 Nextjs is providing built in blur image in Image component. After spending hours I found this article

First you need to update your nextJs app to 10.2.4 or above version.

yarn add next@10.2.4

Then implement your nextJs Image component with two addtional props blurDataURL and placeholder. Check the code example below.

<Image
   className="image-container"
   src="/images/high-quality-image.jpg"
   width={250}
   height={240}
   quality={75}
   blurDataURL="/images/path-to-blur-image.jpg"
   placeholder="blur"
/>

Next.js Update:

Next.js now support placeholder="blur" you can use it in the image component:

<Image src={author} alt="Picture of the author" placeholder="blur" />

With Next.js v11, this is supported internally:

import Image from 'next/image';
import someImg from 'path/to/some/image.png';

// ...

<Image src={someImg} placeholder="blur" />

References:

Also, this issue discussed a whole lot of alternatives, which can be helpful if you are using lower versions or trying to use this with non-static images.


Official demo: https://image-component.nextjs.gallery/placeholder

The example can be animated if you want: (related)

import Image from 'next/image';
import { useState } from 'react';

import ViewSource from '../components/view-source';
import mountains from '../public/mountains.jpg';

const PlaceholderBlur = () => {
  const [loaded, setLoaded] = useState(false);

  return (
    <>
      <ViewSource pathname="pages/placeholder.js" />
      <h1>Image Component With Placeholder Blur</h1>
      <Image
        alt="Mountains"
        src={mountains}
        placeholder="blur"
        width={700}
        height={475}
        className={loaded ? 'unblur' : ''}
        onLoadingComplete={() => setLoaded(true)}
      />
      <style jsx global>{`
        .unblur {
          animation: unblur 1s linear;
        }

        @keyframes unblur {
          from {
            filter: blur(20px);
          }
          to {
            filter: blur(0);
          }
        }
      `}</style>
    </>
  );
};

export default PlaceholderBlur;

Result:


How does this compare with other options??

  • You get to keep using the awesome next/image instead of unoptimized img tag or not-so-optimized third-party implementations.

  • No need to add additional dependencies, i.e. bundle size won't be effected much.

  • No need to manually generate a tiny image to show as preview. Next.js automatically generates a very small (<10px) image for you.

import Image from 'next/image';
import imageUrlBuilder from '@sanity/image-url';

import sanity from '../../utils/sanity';

export function urlFor(source) {
  return imageUrlBuilder(sanity).image(source);
}

const SanityImage = ({ src, width, height, alt, ...props }) => (
  <Image
    src={urlFor(src).width(width).height(height).url()}
    width={width}
    height={height}
    layout="responsive"
    placeholder="blur"
    alt={alt || 'kickoff'}
    blurDataURL="/images/coverImage.png"
    {...props}
  />
);

export default SanityImage;


Related