loading...

Easy "Blur Up" Image Loading with React Hooks

benhoneywill profile image Ben Honeywill Originally published at benhoneywill.com ・2 min read

Nb. I originally wrote about this technique on my blog, and there are interactive examples there so if you find this interesting check it out! 😊

What is "Blurring Up" an image?

Sometimes big images take a bit too long to load, and it can ruin users' first impressions of a site.

"Blurring Up" an image involves initially rendering a very small image, scaling it up and then applying a Gaussian Blur.

This means you get a low-res blurry representation of the image while the full-size image loads, and you never have to worry about your users looking at blank boxes where images should be.

Implementing this in React

I wanted to create a neat and tidy reusable React Hook that I could use in various components for Blur Up image loading. Here is what I ended up with.

import React from 'react';

const useProgressiveImg = (lowQualitySrc, highQualitySrc) => {
  const [src, setSrc] = React.useState(lowQualitySrc);

  React.useEffect(() => {
    setSrc(lowQualitySrc);

    const img = new Image();
    img.src = highQualitySrc;

    img.onload = () => {
      setSrc(highQualitySrc);
    };
  }, [lowQualitySrc, highQualitySrc]);

  return [src, { blur: src === lowQualitySrc }];
};

export default useProgressiveImg;

This is a hook which accepts two arguments: a low-quality image src, and a high-quality image src.

By default this hook will return the src of the low-quality pixelated image. Once the higher quality image has loaded, it will return that instead. This is achieved by adding an event listener to a new Image object. The src attribute of this Image is set to the src of our high quality image, so the event listener fires once the full-size image has loaded.

Once that image has loaded we switch from returning the pixelated image to returning the full-size image.

You may have also noticed that this hook returns a second value, which is an object containing a value I have called blur. We can use this to know whether or not we need to "blur" the image. If the current src being returned is that of the low-quality image, then we should blur the image, as that is the nasty pixelated one.

Usage

Here is an example of how to use this hook to get the desired "blur up" effect.

import React from "react";
import useProgressiveImg from "./useProgressiveImg";

const BlurredUpImage = () => {
  const [src, { blur }] = useProgressiveImg(
    "./tiny.jpg",
    "./large.jpg"
  );

  return (
    <img
      src={src}
      style={{
        width: 200,
        filter: blur
          ? "blur(20px)"
          : "none",
        transition: blur
          ? "none"
          : "filter 0.3s ease-out"
      }}
    />
  )
}

In this example tiny.jpg should be a very small version of the full-size image large.jpg.

I have used inline styles here for simplicity's sake, but you could also use the blur value to toggle a class, or pass it in as a prop to a styled component. The important thing here is that we are adding a CSS blur() filter if the image hasn't loaded yet. The transition makes the transition between the blurred and non-blurred states nice and smooth.

Thanks for reading

Let me know what you think of this handy hook in the comments.

Posted on by:

benhoneywill profile

Ben Honeywill

@benhoneywill

I am Ben Honeywill. I'm a Front-End Engineer from the UK. I work for @LushLtd. Web development ❤️ Javascript 🤘

Discussion

markdown guide