Cross-browser filters with CSS and SVG

Warning This article was written over six months ago, and may contain outdated information.

For some time now, since Safari 6 and Chrome 18 were released, we’ve been able to use the –webkit-filter CSS property to apply graphical filters to HTML content. But it seems that many people aren’t aware that you can also do this in Firefox and — within a very limited set of parameters — IE9 and above.

The reason for this is that all of these browsers support SVG filter effects, and CSS filter effects are basically shorthand functions that apply predefined configurations of SVG filters.

CSS and SVG filters

Applying filters in CSS is very easy; here’s an example of how you’d apply Gaussian blur to an element:

E { -webkit-filter: blur(3px); }

The blur() function is a shorthand for SVG’s feGaussianBlur filter, which is defined in SVG markup like this:

<filter id="blur">
  <feGaussianBlur stdDeviation="3"/>
</filter>

The value of the stdDeviation attribute is in pixels, matching the value supplied to the blur() function. To apply this filter to an element in Firefox you pass its id value into the url() function of the unprefixed filter property:

E { filter: url('filters.svg#blur'); }

The result looks like this:

Broken Links logo
This image has a blur applied with a CSS/SVG filter.

In my example I’m linking to an external SVG file (filters.svg) where I’ve predefined a handful of filters, but you can also embed the code in the same page as your target element and use only the id value.

Some CSS filter functions mask much more complexity; the drop-shadow function, for example, is pretty simple:

E { -webkit-filter: drop-shadow(5px 5px 2px black); }

But the same function in SVG combines offset positions, fill colours, and Gaussian blur, then merges them all together before applying:

<filter id="drop-shadow">
  <feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
  <feOffset dx="5" dy="5" result="offsetblur"/>
  <feFlood flood-color="#000000"/>
  <feComposite in2="offsetblur" operator="in"/>
  <feMerge>
    <feMergeNode/>
    <feMergeNode in="SourceGraphic"/>
  </feMerge>
</filter>

The output is the same, however:

Broken Links logo
This image has a drop shadow applied with a CSS/SVG filter.

If you want to use this technique to apply filters in Firefox there’s an excellent page on MDN which shows each CSS filter function and its equivalent SVG filter markup.

While defining filter effects in this way lets us use them in Firefox, there are a few drawbacks to this approach; as all the values are in the SVG markup, you lose the ability to change them using CSS alone, and it becomes more complicated to animate them.

Internet Explorer

I mentioned at the start of this article that you can apply SVG filters in IE9+, but there are some major drawbacks: for a start, they can’t be applied with CSS, not even in the way Firefox currently does. The only way to apply filter effects to an element in IE is to make the element part of the SVG markup; so if you want to apply a filter to an image you must use the image element inside the svg element, with the filter reference as the value of the filter attribute:

<svg>
  <defs>…</defs>
  <image xlink:href="/wp-content/uploads/2013/11/logo-no-bg.png" width="200" height="158" filter="url(#desaturate)" />
</svg>

In this example I’m using the feColorMatrix filter to completely desaturate the image, as shown below (inspect the element to see the full markup required):


This image is desaturated with an SVG filter.

To be clear, all browsers can use this method, but the big limitation in IE’s implementation is that you can only apply filters to images (as above) or text, and not chunks of HTML. Other browsers support the foreignObject element, which allows you to include HTML inside your SVG:

<foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" filter="url(#blur)">
  <div xmlns="http://www.w3.org/1999/xhtml">
    <h1>Elephants</h1>
  </div>
</foreignObject>

It’s somewhat disappointing that IE has yet to implement foreignObject.

These drawbacks severely limit the usefulness of SVG filters in IE, certainly compared to the current implementations by the other browsers. If you want to play around with filters in IE a little more, there’s a useful SVG filters test page.

Browser Consensus

For filters to reach their full potential, a few things need to happen: IE should implement foreignObject; Firefox should implement CSS filter functions (work is underway); and all other browsers should implement the url() function that Firefox has, allowing for new and more finely tuned filters.

For now, there is an excellent CSS filters polyfill available which provides filter support to Firefox and older versions of IE, using the non-standard DirectX filters which were removed from IE10+.

4 comments on
“Cross-browser filters with CSS and SVG”

  1. […] Cross-browser filters with CSS and SVG | Broken Links […]

  2. […] Cross-browser filters with CSS and SVG – For some time now, since Safari 6 and Chrome 18 were released, we’ve been able to use the –webkit-filter CSS property to apply graphical filters to HTML content. […]

  3. Units in an SVG Filter aren’t necessarily pixels though, they’re whatever units are defined in the viewBox. This defaults to CSS pixels, but if you’re using em’s or pts or whatever, this is what your filter units are going to be. It’s also possible to use relative sizing inside SVG filters.

    (Also, I think that IE10 was the first browser to support SVG filters, not IE9 — you might want to check that.)

  4. Image with CSS Shadow

    http://www.corelangs.com/css/box/image-shadow.html

    css shadow