What is a Blurhash?

Blurhash is an algorithm to save a tiny version of an image while the high resolution version is being fetched or for NSFW content warnings.

I first stumbled across blurhash through Mastodon a few years back, but they're not the only ones using it, apparently Wolt themselves and Signal use it as well. In short, it's a string that looks like a very blurry image, which can be scaled seemlessly.

eKR2}TXUXo4TtS_M%LxatRad?wMxVs.8WBDONHIpRPX9%gt7n$NGj?

By now there's lots of implementations for both en- and decoders listed on their github repo, which makes it really easy to implement.

Why should I use a Blurhash?

For me, there are two good reasons, performance and more fine-grained control for the users.

Performance

If you're able to render a blurhash before a high resolution image is loaded, it gives you something to render into the placeholder element that will tell the visitor that something will be there soon and you can mitigate Cumulative Layout Shift (CLS), which will improve the overall performance of your page load speed.

This may seem counter-intuitive, but rendering an image with unknown dimensions at the top of the page while the page loads will likely cause the browser to re-calculate the position of all elemnents that occur after it, which we want to avoid.

An element that you could use instead of implementing images directly on a blog could look like this:

<div
  className="blurhash-image"
  data-blurhash="eKR2}TXUXo4TtS_M%LxatRad?wMxVs.8WBDONHIpRPX9%gt7n$NGj?"
  data-img-src="/assets/example-dog.jpg"
  style="width: 400px; height: 200px;"
>
</div>

and with a JavaScript library like fast-blurhash you can pick up the data-blurhash value and render it to a canvas element when the page or component loads. When your real asset is available you can swap it out.

If you want to keep the initial page load as small as possible, just wait for the element to come into view through an intersectionObserver. You can start loading the image asset if it's close to the scroll depth of the user, remove the canvas element and substitute it with the img tag.

One of the things crucial for performance is to know the dimensions of the element beforehand, so just not loading the images at first has a limited effect.

Additional Control for your Users

Another reason to use a blurhash instead just rendering the video is to let users decide if they can or want to view a specific type of content in their feed right now. If you're scrolling through your timeline at work, you maybe want to display the recent upload of your favourite nude photographer as a blurry box and only reveal the actual shot after an extra click, like for example Reddit and Mastodon encourage:

reddit nsfw mode

Source: r/analog post

Technically reddit does not use blurhash, but, at the time of writing, a combination of a processed jpg, which their servers blur, and a CSS blur filter.

Mastodon on the other hand uses the blurhash algorithm which saves some bandwith compared to having an actual image file, but emits less immediate detail:

Mastodon NSFW mode

Source: Mastodon post

Try it out

If you want to try out how your blurhash previews would look, you can play a bit on the blurhash playground. It's still a bit rough around the edges, but it supports different aspect ratios in contrast to the official one website.

The images are not leaving your browser, but are processed by the TypeScript library in that very browser window.

Tagged with: #blurhash

Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!