An Introduction To CSS Filters

Image editors gives us the ability to add all sorts of effects. You can change the colors in an image, add a blur, adjust lighting effects, and even blend multiple images together. If you’ve been working with images and graphic editors for awhile, you know to make these changes non-destructively, applying them in layers separate from the original image.

But once the image is live on a website, making additional changes or tweaking those non-destructive effects still requires downloading the image, opening it in your image editor, making the changes, saving the image, and uploading it again to your server. For some effects there’s a better way.

About a month ago I finished a series on SVG filters and I mentioned in that series that some of the SVG filters have come to CSS. Instead of creating the effect you want with an SVG filter you can apply a simple CSS filter, the same as you would any other CSS property.

Today I want to start a short series looking at the filters CSS provides. I’ll show you how to use them and I’’ll compare each to its SVG counterpart.

Which is Better, CSS or SVG?

Before I get started, you might be wondering why you’d opt for a CSS filter instead of one written with SVG. Are CSS filters better than SVG filters? Is it the other way around? Why choose one over the other?

The answers comes down to a few things. CSS filters are generally easier to work with. They typically require less code and using them is similar to learning any other CSS property and its possible values. However, the greater simplicity comes with the cost of control. The extra code when working with SVG filters offers more control over the effect you want to achieve.

SVG filters have more browser support. IE and Opera Mini don’t offer support for CSS filters at all. Edge browsers offer partial support, though they support everything other than the url() filter which I’ll talk about next week. Also note that the SVG spec is candidate recommendation, while the CSS filter spec is still a working draft, meaning it can change.

Ultimately, which one you decide to use will depend on what kind of filter you need and what you want to do with it. It will also depend on which browsers you need to support.

One last consideration is performance. This article suggests that CSS filters might be ever so slightly faster, but likely imperceptible to people. Where you’ll more likely see a performance differences is between the different filters, regardless of whether or not you use SVG or CSS. For example, it takes more time to apply a blur to an image than it would to apply a color change and the greater the blur radius, the longer it will likely take to display.

My recommendation is to stick to SVG filters for the moment, but learn how CSS filters work. Once they have a little more support, you’ll probably opt for the CSS filter whenever it’s an option.

How CSS Filters Work

CSS filters are essentially shortcuts to SVG filter primitives with a particular set of values. It’s one reason you should understand how SVG filters work even if you eventually prefer working with filters in CSS.

CSS filters follow the form.

[code type=css]
filter: none | <filter-function>+;
[/code]

The value none is not particularly interesting. You’d use it if you want to turn off a filter or ensure one isn’t accidentally set. Let’s focus on the filter-functions.

To apply a filter to an HTML element you might have code that looks like this.

[code type=css]
.filtered-image {
filter: filter-function(function values)
}
[/code]

In the code above, I presumably have an image in my HTML with a class of filtered-image applied. The selector takes a single filter property which has as its single value a filter-function. The filter-function itself will accept values.

You can apply multiple filter-functions to a single filter property. Note that there’s a space between filter-functions, but no comma between them. Remember not to include the comma. It’s easy to forget.

[code type=css]
.filtered-image {
filter: filter-1(filter-1-values) filter-2(filter-2-values)
}
[/code]

If you prefer you can set multiple filter-functions with each function on its own line. Your CSS will ignore the extra whitespace. Personally I find writing it this way makes it easier to see what’s going on.

[code type=css]
.filtered-image {
filter:
filter-1(filter-1-values)
filter-2(filter-2-values)
}
[/code]

Again, note the lack of commas between filter-functions. White space only should separate one from the next.

If the filter-function tries to reference a non-existent filter, the entire filter chain is ignored and no filter will be applied to the element.

CSS provides 11 filter functions. Here they are in the order I’ll talk about them. Today I’ll cover blur(). Next week I’ll talk about url() and drop-shadow() and so on.

blur() – feGaussianBlur

url() – Fragment Identifier

drop-shadow() – Multiple SVG filter primitives

grayscale() – feColorMatrix

hue-rotate() – feColorMatrix

saturate() – feColorMatrix

sepia() – feColorMatrix

brightness() – feComponentTransfer

contrast() – feComponentTransfer

invert() – feComponentTransfer

opacity() – feComponentTransfer

To the right of each function is the SVG filter primitive from which it arises. The url() and drop-shadow() functions don’t come from a single filter primitive. The former is used as a fragment identifier and the latter comes from a combination of primitives to create the drop shadow effect.

You can probably guess what most of these do. Don’t worry if you can’t as I’ll walk through examples of each over the next few weeks.

There used to be mention of a custom filter that let you work with CSS shaders and go beyond what any of the filter-functions can do. Unfortunately some issues arose with them and as far as I know work has stopped and browsers won’t be supporting shaders or custom filters.

When you add a CSS filter it’s applied before any clipping, masking, or opacity. This is the same as it is for SVG filters. When a filter is applied it creates a new stacking context. All descendent elements are rendered together with the filter being applied to everything as a single whole.

CSS filters have no effect on the geometry of CSS boxes, though filters can paint outside of an element’s border box. Any part of an image or graphic element, including backgrounds, borders, and text are affected by a filter. Finally, the operations of a filter are applied in the element’s user coordinate system.

Let’s get to the functions.

The blur() filter-function

As you can probably guess from the heading of this section, the blur() filter-function adds a gaussian blur to an element. It’s a shortcut for the SVG filter primitive, feGaussianBlur.

[code type=css]
blur() = blur( )
[/code]

You pass the function a length, which becomes the radius for the blur. The radius defines the standard deviation value in the Gaussian function that ultimately determines how much to blur the original graphic.

The length that gets passed can’t be a percentage. You do need to set the units and px, em, cm, in, are all valid. If you forget the units as in blur(5) no blur will be applied. The value must also be positive as negative lengths don’t make sense.

Let’s apply a CSS blur to an image. First we add the image to an HTML file. Note that I added a class of strawberry to the image.

[code type=css]

[/code]

If you followed some of my previous posts about SVG filters, you’ll recognize my image of the Strawberry Fields memorial in Central Park. If not, here it is.

The filter can be added inline, in the head of your HTML, or in a separate CSS file. Here I created a selector for the .strawberry class and added a single filter property to it. The value of the filter property is the blur() filter-function and I set the value of the function to 5px.

[code type=css]
.strawberry {
filter: blur(5px);
}
[/code]

Note: In examples throughout this series I’ve used inline CSS to show the results as it makes them a little easier present. When I show the code though, I’ll write it as if it comes from a separate CSS file.

Here’s the result, which you can see is a blurry version of the original.

The CSS function replaces the following SVG feGaussianBlur filter primitive.

[code type=css]

[/code]

Notice the SVG primitive can accept two values for radius, one each for the x and y directions, where the CSS function accepts only the one radius, which is used for both directions. It’s one example where the SVG filter gives you more control than the CSS filter.

Let’s leave things here. I’ll pick up again next time with more filter-functions.

Closing Thoughts

CSS filters are effectively shortcuts for certain SVG filter primitives that make it easy to apply some common effects. They’re generally simpler to use than their SVG counterparts, but in exchange for the simplicity they give you a little less control over the effect.

Hopefully you can see, even with only one example, that CSS filters are pretty easy to use. You add the filter property to the selector you want to modify and add the filter-function(s) you’d like to use as a value to the property.

The rest is understanding how the specific functions work and what values each accepts and expects. I showed you the blur() filter-function today and over the next three weeks, I’ll cover the rest.