August 27, 2021
Loading Images With the “Blur Down” Technique
An experimental approach to deblurring images on load
⚠️ Disclaimer
- Please avoid copying any code until reading the article in full. This is an experimental technique that comes with caveats.
- Examples on this page use a CSS-only Low Quality Image Placeholder (LQIP) generated via plaiceholder.co, but this isn't a hard requirement. You'll see the same with results strategies such as Base64 and more.
- Yes, I did just start an article about deblurring images on load by deblurring an image of Blur on load.
Earlier this week, I made the most of a long train journey to explore an idea; what if I could recreate a "bias lighting" effect for images on joebell.co.uk?
After a few hours of experimentation on a cortisol-inducing "premium" WiFi connection, I came up with a questionable but visually-impressive concoction of filter
and backdrop-filter
applied to a Low Quality Image Placeholder (LQIP). I quickly added a "blur up" transition on image load, and posted the results to twitter.
Despite the tweet being well received, I decided against using the effect. Bright and colourful images looked great, but darker images – in my use-case, nearly all of my images – gave an effect more akin to a littered newspaper bleeding ink from the rain. A fun experiment, but not practical for my use-case.
Rereading the tweet every time a notification came through – let's be honest, we all do it – one thing started to stick out to me. The "blur up" on load transition was fine, but it felt unnatural. What would make it feel more photorealistic?
Let's imagine you're about to take a photograph of someone with an SLR camera. You look through the viewfinder to see the subject is out of focus; a blur. As you slowly start moving the focus ring, the blur morphs into a sharp image of your subject.
It got me wondering; could such an effect be achieved in CSS? An experiment that led to a wildly popular result and the unexpected existence of this post.
"Blur Up"
Before exploring alternatives, let's take a look at how the popular "blur up" technique works.
The transition occurs between 2 states, affecting 2 elements that are stacked on top of each other on the z-axis:
- Image not loaded
- LQIP – blurred to hide pixel detail and scaled to hide the fading edges.
- Image – visually hidden, with
opacity
set to0
.
- Image loaded
- LQIP – unchanged.
- Image – visible, with
opacity
set to1
.
The order or method of stacking doesn't matter too much, the effect remains the same. By transitioning only the opacity
value of a single element, we can achieve a relatively nice-looking and high-performance transition.
However, the question still remains; could it be more photorealistic?
"Blur Down"
Let's flip the transition on its head. How could the image morph into the LQIP, like a camera when adjusting focus?
For the transition end – the full-size image – to look as close as possible to the transition start – the LQIP, the blur and scale styles need to be applied to both elements.
Similarly to the "blur up" transition, this occurs between 2 states, affecting 2 elements that are stacked on top of each other on the z-axis:
- Image not loaded
- LQIP – blurred to hide pixel detail and scaled to hide the fading edges.
- Image - visually hidden, with
opacity
set to0
, as well as a blur and scale that matches the LQIP.
- Image loaded
- LQIP – unchanged.
- Image – visible, with
opacity
set to1
, as well as deblurred and scaled down to its original size.
It doesn't offer the same "bokeh" effect that you would expect with an SLR camera, but it certainly feels more natural when compared side-by-side to the "blur up".
Caveats
One of the biggest issues with "blur up" is that an expensive property is being transitioned – filter
.
When testing on my 2018 Macbook Pro, a relatively large drop in frame rate could be measured but not enough to be seen. It's safe to assume that users on low-end devices would not be so lucky.
Even with a last resort of using will-change
to give the browser a hint, we cannot guarantee that filter
will transition smoothly, and we cannot provide an escape hatch for those scenarios…
/**
* We *can* respect a user's motion preference
*/
@media (prefers-reduced-motion: no-preference) {
/**
* We *cannot* be 100% sure that the browser can
* transition `filter` effectively.
* (this will always run, regardless)
*/
@supports (transition-property: filter) {
transition: 1.2s ease;
transition-property: filter, opacity, transform;
}
}
Which Blur Is Best?
It might appear odd that I would create the "blur down" effect, use it on my personal site, write a blog post about it and then advise you that you shouldn't use it; but that's exactly what's about to happen.
You probably shouldn't use "blur down".
If you do, you should at least strongly consider the caveats.
If the "blur up" transition is smooth for you, it's because:
- My personal site isn't very image-heavy.
- You're privileged enough to own a relatively high-end device with a GPU capable of transitioning
filter
.
The best blur transition is the one that will engage your users. It's down to you to decide whether visual quality is more important than performance.
Most of all, this transition was just an experiment – I was just having fun, I'm not advocating for a change!
Perhaps I'll experiment further and combine the "blur down" effect with Surma's "Animating a Blur" strategy to alleviate performance issues? Perhaps I'll even abandon the technique altogether?
Perhaps you will find something even better? Experiment! Blur the boundaries of CSS. You may be surprised with what you'll find.