Introduction to SVG Filters

SVG filters are the bomb 💣, if I say so myself! They allow to apply visual effects like drop shadows, gaussian blurs, color manipulation or even distortion on any HTML or SVG element on your page. You read that right, SVG filters are not just for SVGs, they are defined in SVG markup, but can then be applied to any element, as you’ll see here.

If you think that CSS filters are powerful, wait until you see what SVG filters are capable of! In fact, behind the scenes, CSS filters simply use a subset of the SVG filter implementation.

I had the pleasure of getting acquainted with SVG filters when working on a duotone generator, and here I hope to share some of what I’ve learned.

SVG Filter Basics

An SVG filter is defined within a <filter> element and, within that element one or more filter primitives can be used. An example of a popular filter primitive would be <feGaussianBlur> to add a gaussian blur effect. Let’s see it in action:

<svg version="1.1" width="0" height="0">
  <filter id="gaussian-blur">
    <feGaussianBlur stdDeviation="12 0" />
  </filter>
</svg>

This filters, when applied on an element, will create a gaussian blur of 12px radius on the X axis and no blur on the Y axis. Here’s the result on an SVG graphic, without the filter and with the filter applied:

Gaussian blur demo, base graphic Gaussian blur demo, with filter applied

You’ll notice that our SVG definition above doesn’t have a viewbox defined and uses a width and height of 0. That’s because we use that particular SVG only to define our filter, so we don’t want it to take up any visual space on the page. Of course, if you had other things in your SVG, you could just as well have them in the same SVG definition and have it be visible on the page. More on that below when we go over how to apply the filter.

Note also that you can define multiple <filter> elements as part of the same SVG definition. All you’ll have to do is give each filter its own unique id so that it can be referenced later.

Combining Filters

You can easily combine multiple filter primitives within one <filter> element. Here for example, we have a blur with a radius of 3px and a semi-transparent pink drop shadow that’s offset 15px by 15px with a blur radius of 3px as well:

<svg version="1.1" width="0" height="0">
  <filter id="blur-shadow">
    <feGaussianBlur stdDeviation="3" />
    <feDropShadow dx="15" dy="15" flood-color="pink" flood-opacity="0.5" stdDeviation="3"/>
  </filter>
</svg>
Gaussian blur and drop shadow demo, base graphic Gaussian blur and drop shadow demo, with filter applied

When combining multiple filter primitives, by default the first primitive uses the original graphic (SourceGraphic) as its graphic input and any subsequent primitive will use the result of the previous filter effect as its input. You have flexibility over that, however, thanks to the in, in2 and result attributes on primitive elements:

  • in: Specify the input graphic for the filter to be applied on. Can be the keywords SourceGraphic (the initial graphic targeted) or SourceAlpha (the alpha/transparency channel of the source graphic), or it can be one of your own named results.
  • in2: Some filter effects expect two inputs, and in2 is used in those cases to specify the 2nd input. It can take the same values that in can take.
  • result: Specify a name for the result of a filter primitive that can then be referenced as the in or in2 value of another primitive. You’ll often see the names being uppercased, by convention.

Applying Filters

Now that we know more about defining our filter effects using the <filter> element and filter primitive elements, it would seem appropriate that we look at how we apply them to our elements!

Using the CSS filter property

Making sure that the SVG filter definition is part of the page, you can simply reference it by it’s id using the CSS filter property. Let’s use the filter from our previous example on a standard HTML <button> element:

.btn-filter {
  filter: url(#blur-shadow);
}

And this works for any HTML element, even img, so you can therefore easily apply your SVG filters to normal images on your page.

Using the SVG filter attribute

Another way to apply an SVG filter that you’ve defined is to set the filter attribute of an SVG element to point to the filter id:

<svg viewBox="0 0 875 337" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <filter id="blurry">
    <feGaussianBlur stdDeviation="7 5" />
    <feDropShadow dx="0" dy="25" flood-color="var(--code)" flood-opacity="0.25" stdDeviation="5"/>
  </filter>

  <circle fill="var(--code)" cx="265" cy="169" r="88"></circle>
  <circle filter="url(#blurry)" fill="var(--code)" cx="611" cy="169" r="88"></circle>
</svg>

Filter Region

In our previous example you’ll notice that part of the drop shadow is clipped, because it falls outside of what’s known as the filter region. By default, this region gives you a 10% padding, but you can override it when you need a larger region in order for the effect to be fully visible.

For example, a fix for the previous example would be the following, with x, y, width and height specified on the filter element, which give us a 20% padding instead of the default of 10%:

<svg viewBox="0 0 875 337" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <filter id="blurry" x="-20%" y="-20%" width="140%" height="140%">
    <feGaussianBlur stdDeviation="7 5" />
    <feDropShadow dx="0" dy="25" flood-color="var(--code)" flood-opacity="0.25" stdDeviation="5"/>
  </filter>

  <circle fill="var(--code)" cx="265" cy="169" r="88"></circle>
  <circle filter="url(#blurry)" fill="var(--code)" cx="611" cy="169" r="88"></circle>
</svg>

Filter Primitives

Filter primitives all start with the letters fe, for filter effect and there are a total of 17 available filter primitives. Here’s a summary of them:

  • feBlend: Blend two graphics together using using a blend mode (e.g.: soft-light), just like you’d do in a graphic editing software like Adobe Photoshop.
  • feColorMatrix: Apply a transformation on the matrix created by the 4 channels (red, green, blue and alpha). Can get a bit complicated, but packs a lot of power.
  • feComponentTransfer: Remap the red, green, blue and/or alpha channels using a function. Also very powerful.
  • feComposite: Create a composite of two input graphics using an operator to determine the composite effect.
  • feConvolveMatrix: Used to apply a matrix convolution filter effect. It sounds fancy and complicated, but it can be used to add effects like sharpening or bevel/emboss.
  • feDiffuseLighting: Used to add realistic-looking light to a graphic, using the alpha transparency values in the graphic as a bump map for the light.
  • feDisplacementMap: Takes two input graphics and uses the input of the 2nd graphic as values to displace the values in the 1st graphic.
  • feDropShadow: Adds a drop shadow to the graphic.
  • feFlood: Fills the graphic with a solid color.
  • feGaussianBlur: Adds a gaussian blur to the graphic.
  • feImage: Useful to fill a graphic with another external image.
  • feMerge: Merge two graphics together. Useful to allow multiple primitives to be merged together instead of applied one after the other.
  • feMorphology: Erode or dilate an input graphic. It’s hard to explain in words, so refer to this article for some great examples.
  • feOffset: Simply offset the input graphic.
  • feSpecularLighting: Similar to feDiffuseLighting, but with a specular source of light. As an example, direct sunlight would be specular light, and cloudy daylight would be diffuse lighting.
  • feTile: Fill the graphic with a tiled pattern.
  • feTurbulence: Generate Perlin noise. Can be useful to generate organic textures like cloud or wood textures.

Some of them get quite complex and the whole topic in general could easily fill a whole book. If you want to learn more about a particular primitive, I encourage you to head over to Sara Soueidan’s articles on Codrops, where she covers many of them in detail.

Further Reading

This tutorial only scratched the surface, so if you want to learn about SVG filters more in-depth, I recommend having a look at these cool resources 😎:

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#