Filters are a very large part of SVG because they are very powerful. Applying a filter to any basic shape can subtly change it to make it look much better, but also transform an object to the point you can’t recognize it anymore. There are lots of filters available, and every element can have one or multiple attached. If you hadn’t noticed: by default, no filters are attached to anything.
One thing you should understand very well, is the fact that filters work on a pixel level. If you scale an SVG graphic, the filter will try to scale with it by recalculating the filter, but it will still just be a bunch of pixels. Filters read what you put into it as a bunch of pixels with the colour channels R, G, B and A - each with a value between 0 and 1 - and every action you perform is about changing the values of all pixels in one way or another. Now we can continue with the fun parts!
Filters work using the same two-step method as most other things in this course: define the filter somewhere inside a
<defs> element, and use a special attribute on an element to use this filter. Filters, however, can be chained. This means that one filter can have multiple filter elements within it, which each build on the output the previous one produced. For example, I could first blur a shape, and then apply drop shadow to the blurred shape (instead of the original).
Because of this, we always need to group the steps of our filter within a
<filter> element. The syntax is:
<filter id=”filterName” x=”xPos” y=”yPos” width=”width” height=”height”>
… all the filter elements you want …
y attributes position the filter relative to whatever graphic it’s used on (default is
-10%). For example, if you want a drop shadow to appear at the upper left corner, you’ll need to offset the filter by a negative amount to make room for it. The
height attributes serve a similar purpose: most filters end up a different size than the graphic they’re used on (default is
To apply a filter to any shape, all you have to do is use this attribute:
<svg> <defs> <filter id="ourFilter" x="0" y="0" width="100" height="100"> </filter> </defs> <rect x="10" y="10" width="100" height="100" filter="url(#ourFilter)" /> </svg>
The Filter Primitives
As you’ve probably noticed, last example didn’t do anything. That’s because we’ve defined a filter container and given it a nice name, but there are no filter primitives inside it. These are the actual elements that have a certain effect on the graphic, which you can partly influence using special attributes.
There are a lot of them, and I think just throwing them in a list now wouldn’t clear things up, which is why I’ll first demonstrate their general working.
Every filter primitive has two standard attributes:
in attribute determines what is put into the filter. The value
SourceGraphic simply uses the shape the filter is called upon as input, while
SourceAlpha inputs the shape’s alpha. Besides these standard values, you can also use the output of other filters as input.
result attribute is used for exactly that: specifying the output of a filter. This way you can chain lots of filter primitives in any way you like, by using the output of a filter as the input for the next.
The last filter primitive that is used within a filter, doesn’t need the
result attribute set. Its result is automatically used, no need to make up a name for it.
It’s very important to understand that a filter acts on the original graphic. You’ll need to go through some effort if you want to maintain the original shape together with the filter. This is done by merging the original shape and its filter together, and that will be our first filter primitive!
The syntax is:
<feMergeNode in=”SourceGraphic” />
Of course, you can put many more nodes in there if you want, although it would make things quite complex.
<svg> <defs> <filter id="ourFilter" x="0" y="0" width="100" height="100"> <!-- You'll learn about this blur primitive next section--> <feGaussianBlur stdDeviation="15" result="blur"/> <feMerge> <feMergeNode in="SourceGraphic" /> <feMergeNode in="blur" /> </feMerge> </filter> </defs> <rect x="10" y="10" width="100" height="100" filter="url(#ourFilter)" fill="red"/> </svg>
To blur a graphic around the edges, use
<feGaussianBlur stdDeviation=”value” />
The value determines how wide the blur is – a low value creates a slight glow around the graphic, while a high value almost makes it unrecognizable.
<svg> <defs> <filter id="ourFilter" x="0" y="0" width="100" height="100"> <feGaussianBlur stdDeviation="50" /> </filter> </defs> <rect x="10" y="10" width="100" height="100" filter="url(#ourFilter)" fill="red"/> </svg>
For a drop shadow, we’ll need (at least) two primitives.
<feOffset dx=”offsetX” dy=”offsetY” />
This simply offsets whatever is put into it by (offsetX, offsetY) amount.
<feBlend in2=”secondFilter” mode=”blendMode”/>
This requires a second in attribure,
in2, which it blends with the regular
in attribute. This is very similar to merging, except for the fact that you can determine the way they are merged with blendMode. The possible values for this are:
Usually, a drop shadow is also blurred, for which you can use the command from the previous section!
<svg> <defs> <filter id="ourFilter" x="-10%" y="-10%" width="200" height="200"> <feOffset dx="15" dy="15" result="offset"/> <feGaussianBlur in="offset" result="shadow" stdDeviation="15"/> <feBlend in="shadow" in2="SourceGraphic" /> </filter> </defs> <rect x="10" y="10" width="100" height="100" filter="url(#ourFilter)" fill="black"/> </svg>