Setting CSS Blur Filter to Zero on a Retina Screen

Hero image for Setting CSS Blur Filter to Zero on a Retina Screen. Image by Sebastian Muller.
Hero image for 'Setting CSS Blur Filter to Zero on a Retina Screen.' Image by Sebastian Muller.

This Article is Over Eleven Years Old...

Things can and do move very quickly in tech, which means that tech-related articles go out of date almost as soon as they have been written and published. If you are looking for up-to-date technical advice or opinion, it is unlikely that you will find it on this page.

You may find that my recent articles are more relevant, and you are always welcome to drop me a line if you have a specific technical problem you are trying to solve.

Despite fairly widespread uptake in the development and browser community, the filter property is still a relatively immature part of CSS (the module specification is still currently only a working draft). In the case of using the blur() filter, the draft specification notes that a CSS length parameter is used to define the radius of the Gaussian function applied:

The passed parameter (the radius) defines the value of the standard deviation to the Gaussian function. The parameter is specified a CSS length, but does not accept percentage or negative values.

In layman's terms: blur() needs a numerical value, with or without a unit value (px, em, etc); the bigger the value, the more blurry the element you apply it to will render (assuming the correct use of vendor prefixes and browser support).

At present, prevailing wisdom suggests the preemptive use of each of the major vendor prefixes. whether those vendors currently support the property or not. As an example, if you wanted to add a 10px blur to an element using CSS, you would end up with a piece of CSS that looks something like this:

.blur-me {  filter: blur(10px);  -webkit-filter: blur(10px);  -moz-filter: blur(10px);  -o-filter: blur(10px);  -ms-filter: blur(10px);}

Of course, you could also include an SVG filter in there as a final fallback, but given how minimal browser support currently is for all filter effects if it simply wouldn't be acceptable for your development to degrade back to nonblurred for the 56.59% of browsers that don't currently support it, then you might need to consider another route that doesn't use the effect at all.

One of the nice things about filters is that they can be animated and used in conjunction with CSS transitions. I use it myself on the previous version of this website to blur the main website content when the mobile flyin navigation is opened, which is where I came across a stumbling block. My CSS looked something like this:

.page {  filter: blur(0);  -webkit-filter: blur(0);  -moz-filter: blur(0);  -o-filter: blur(0);  -ms-filter: blur(0);}.nav-open .page {  filter: blur(3px);  -webkit-filter: blur(3px);  -moz-filter: blur(3px);  -o-filter: blur(3px);  -ms-filter: blur(3px);}

All fairly straightforward: .page would have no blur (blur(0)) by default, and a 3px blur when switched via the parent class (.navopen).

Although this method worked just as expected, it also revealed an interesting bug in the way that WebKit handles display on Apple's retina screens: when viewed on my MacBook Pro the blur never quite fully extinguished itself, retaining a very subtle blur:

Screenshot of blur(0) in Chrome on a retina device.

However, using filter: none still reverted (correctly) back to no blur at all, although that's not an ideal solution if you're using other filters on that same element!

Reverting to the incessant knowledge of Stack Overflow, the answer seems to be that this is a known bug in WebKit (although from all my searching, I couldn't find any mention of it online), and the only answer aside from using none is a combination of using either webkittransform: translateZ(0) or webkitbackfacevisibility: hidden. Both will work, although either may have other unintended effects depending on your situation. Tread lightly.

The nice thing is that since this appears to be solely a WebKit issue, there isn't any need for any other vendor prefixes, although I do opt to include the nonprefixed version of the fix, too for forward compatibility:

.page {  -webkit-transform: translateZ(0)  transform: translateZ(0)  filter: blur(0);  -webkit-filter: blur(0);  -moz-filter: blur(0);  -o-filter: blur(0);  -ms-filter: blur(0);}.nav-open .page {  filter: blur(3px);  -webkit-filter: blur(3px);  -moz-filter: blur(3px);  -o-filter: blur(3px);  -ms-filter: blur(3px);}

What I find most interesting about this is that both the workarounds above share one thing in common: both are used as sortof hacky ways of boosting transition and filter performance by allowing hardware acceleration in WebKit browsers. Perhaps it is nothing more than a coincidence, but I do wonder whether the reason the zerosetting works when using hardware acceleration on these highdensity screens relates to the GPU being designed specifically to process at these subpixel/zero levels, whereas the software acceleration appears to round the blur effect to somewhere inbetween 0px and 1px.


Categories:

  1. Cross‑Browser Compatibility
  2. CSS
  3. Development
  4. Front‑End Development
  5. Image Rendering