Applying Gaussian Blur to HTML elements with CSS

UPDATE (05 January 2012): Christian "Schepp" Schaefer has an excellent article on implementing cross-browser blur with CSS, filters, and SVG titled Effects for the Web. Check it out!


UPDATE (21 April 2011): The the w3's editor's draft for filter effects is getting lots of attention lately - the main focus seems to be on CSS blur right now. The newly proposed CSS blur should behave very similarly to the moz-element hack outlined in this post but will be more performant, easier to implement, and super awesome. It will go something like this: #elementId { filter:blur(3px); }. Sweet.


Update (18 April 2011): It is apparent that I should note that this method should probably be considered a "hack" - and that I would LOVE to see a better (and more cross-browser) implementation. Please feel free to fork the jsfiddle below and 'best' my solution. :-)

 Also, I think I need to clarify as to what this blur effect is, and what it is not:

The effect is intended to work in HTML; no XML content-type, doctype, markup, or extra namespaces are needed.

The effect, as detailed below, will work with HTML5Boilerplate without any modifications whatsoever. You could write a jQuery plugin to automate the process and you wouldn't have to worry about strict XML validation and the other goodies that come with XHTML.

The effect is NOT a text-blur or shadow-like effect. It is much more than that; it can "blur" your images, video, text, backgrounds, gradients, borders, iframes, animations, etc.

Hey there. So, I recently purchased my first Android-powered phone computer (well, technically it was free with the 2 year contract) and while powering it off I noticed the background of the power-off confirmation screen has a gentle gaussian blur. This blurred-background UI is common in desktop (and smart-phone) applications, but not on the web.

Unfortunatly, we don't have a "blur" CSS property (yet) that we can apply to arbitrary elements, and canvas just doesn't cut it. So, if we want to implement a blurred background effect we have to provide an image of a blurred background. "But wait!", you say, "what about SVG?". I love html5boilerplate, I love short doctypes, I love text/html - SVG filters just aren't implemented completely in the HTML5 environment.

But what we do have, at least in Firefox 4, is background-image:-moz-element(#elementID).

New in Firefox 4, the -moz-element extension to the background-image property of elements allows us to display an element, and its descendants, including cross-domain iframes, as a background image. I'm not going to go over the restrictions and details of its implementation; you can read about it on the mozilla hack blog.

What I'll be showing you isn't really gaussian blur, get over it (it is probably some form of box blur).

Check out the Result tab in the jsfiddle for the demo, view the CSS for the good-stuff.

Note: THIS WILL ONLY WORK IN FF4!

See the Pen mGnBE by David Murdoch (@davidmurdoch) on CodePen.

So, what is happening here?
First, we reference our #content element via background-image's -moz-element extension, like this:

background-image:-moz-element(#content);

We then take advanatage of CSS3's multiple background-image support and add the additional -moz-elements required to render our blur.

To calculate how many -moz-elements you need:

numberOfElements = ( (radius * 2) + 1 )2 ) - 4

where radius > 0.

So, a radius of 1px gives needs 5 elements, 2 = 21, and 3 = 45.

We then need to position our background-images. The coordinates for a 1px radius are:

(0,0)
(0,1)
(0,-1)
(1,0)
(-1,0)

and 2px adds on an additional 16 coordinates:

(1,1)
(1,-1)
(-1,1)
(-1,-1)
(0,2)
(0,-2)
(2,0)
(2,1)
(2,-1)
(-2,0)
(-2,1)
(-2,-1)
(1,2)
(1,-1)
(-1,2)
(-1,-2)

...and so on.

Once we've got our background-images in place we need to adjust the opacity of the original element (#content):

opacity = 1 / numberOfElements;

So, for a 2px radius the opacity should be .048 (1px = , 3px = .22)

It should be pretty easy to write a plugin or script to generate the neccessary CSS for you; but I leave that up to the reader (aka I'm too lazy to do it right now).

Disclaimer: This can really hurt performance with a large blur radius. You may be able to omit some -moz-elements if performance becomes an issue.

Comments for this blog entry