How To Add A Drop Shadow With A CSS Filter

Last week I began a series on CSS filters. I talked in general about the difference between CSS and SVG filters and then I showed you how to work with the former. I closed by walking you through the blur() filter-function and showed you an example using the function.

If CSS filters are new to you, you may want to read last week’s introduction post first. If SVG filters are new to you, you may want to start with these.

One of the things I mentioned last week is that most CSS filters are shortcuts for setting particular values on an SVG filter primitive. Today I want to present two filter-functions that are a little different in that more than one SVG filter primitive can be involved. One provides a reference to SVG filters and the other makes it easy to add a drop shadow.

The url() filter-function

The url() filter-function provides a way to apply an SVG filter to an element through a CSS selector. The function creates a reference to a filter element.

Here’s some code you might place in an HTML file. It starts with a relatively simple SVG filter that uses the feColorMatrix filter primitive to change the hues of an element. After the filter I added an image of the Strawberry Fields memorial in Central park, which I used throughout the SVG series. My apologies if you’ve grown tired of the image.

1
2
3
4
5
6
7
8
9
<svg width="100%" height="495">
 <defs>
   <filter id="hue">
     <feColorMatrix type="hueRotate" values="225" />
   </filter>
 </defs>
</svg>

<img class="strawberry" src="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" />

As you might guess, the image would display, but the filter doesn’t do anything as it’s not being referenced. Here’s what it looks like and these are the original color hues for the image.

Had I used SVG instead of HTML to display the image, I could have added a reference to the filter like so:

1
2
3
4
5
6
7
8
9
<svg width="100%" height="495">
 <defs>
   <filter id="hue">
     <feColorMatrix type="hueRotate" values="225" />
   </filter>
 </defs>

 <image xlink:href="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" filter=url(#hue) x="0" y="0" />
</svg>

Note the filter=url(#hue) part near the end of the image code. Here’s the result and you can see the filter has been applied and the hues of the image have shifted 225 degrees around the color wheel.

Note: If instead of an image you see an empty blank space, you’re probably viewing this in Firefox, which doesn’t seem to like the combination of using a filter with WordPress. The code above worked fine outside of WordPress. If you know why it doesn’t work inside WordPress, please let me know.

The CSS filter-function lets you add the reference to the CSS selector. Here’s the original HTML image code without the filter reference. Note that I added a class of strawberry that we can use as a selector.

1
<img class="strawberry" src="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" />

In your CSS file you can use the url() filter-function to reference the #hue filter (the same filter I showed earlier in this section).

1
2
3
.strawberry {
 filter: url(#hue);
}

As you can see in the result, the filter is applied and the hues have again shifted 225 degrees on the color wheel.

It should look exactly the same as the previous example, since the same filter is being applied in both cases. In the first example we referenced the filter in the SVG and in the second we referenced it in the CSS.

One final thing to note is an issue in Firefox, which needs an absolute url in the url() filter-function or it won’t work. It’s one reason I added the reference using inline CSS in the example above. This way I could stick with the relative url #hue instead of having to use an absolute URL.

Just remember in practice you’ll either need to add the url() filter-function in the same file the SVG filter is located or you’ll need to use an absolute url as the reference inside the function.

The drop-shadow() filter-function

There is no feDropShadow filter primitive. To create a drop shadow with an SVG filter, you have to combine multiple primitives inside the filter.

Here’s a filter I used in an example from a previous series to demonstrate the feMerge primitive. The filter takes the alpha channel of the original image, blurs it and offsets it, and then using feMerge, displays the original graphic on top of the new shadow.

1
2
3
4
5
6
7
8
9
10
11
<filter id="drop-shadow">

  <feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur" />
  <feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>

  <feMerge>
    <feMergeNode in="offsetBlur"/>
    <feMergeNode in="SourceGraphic"/>
  </feMerge>

</filter>

In CSS a single filter-function will create the drop shadow and position it behind the source element.

1
drop-shadow() = drop-shadow( <length>{2,3} <color>? 

You can supply either two or three lengths. The first two lengths define the offset in the x and y directions and the third defines the radius for the blur. You don’t need to define the radius, but you do need to define both offsets or the filter will do nothing.

You can also set the color of the shadow and you can supply a hex value or, even better, use rgba() to set the opacity of the shadow.

Here I set the offset to be 16px in each direction and I set a 10px blur. I also chose values for a blue/green shadow.

1
2
3
.strawberry {
 filter: drop-shadow(16px 16px 10px rgba(0,96,128,0.9));
}

Here’s how the filter looks applied to the Strawberry Fields image.

It’s not the most realistic looking shadow, but hopefully you can see you have control over the shadow color.

The CSS filter is very similar to the box-shadow property. The main difference is that some browsers provide hardware acceleration to the filter, which can result in better performance.

For comparison here’s how you would create the same shadow using SVG filter primitives and an SVG image that references the filter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<svg width="105%" height="525">
 <defs>
   <filter id="drop-shadow">

     <feGaussianBlur in="SourceAlpha" stdDeviation="10" result="blur" />
     <feOffset in="blur" dx="16" dy="16" result="offsetblur" />
     <feFlood flood-color="rgba(0,96,128,0.9)" result="flood" />
     <feComposite in="flood" in2="offsetblur" operator="in" result="shadow">

     <feMerge>
       <feMergeNode in="shadow" />
       <feMergeNode in="SourceGraphic">
     </feMerge>

   </filter>
 </defs>

<image xlink:href="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" width="660px" height="495px" filter="url(#drop-shadow)" />
</svg>

Here’s the result, which should look exactly the same as the last example, though it certainly required a lot more code.

Closing Thoughts

The url() filter-function offers a way to apply an SVG filter to any element by referencing the filter in your CSS. This makes it easy to add filters to any HTML element you have on the page.

The drop-shadow filter provides a much simpler way to add a drop shadow than using SVG filter primitives. It’s similar to the box-shadow property except it can have performance benefits in some browsers.

Both of these filter-functions can make use of multiple SVG filter primitives. There is no SVG primitive that creates a drop-shadow on its own and url() can reference filters with as many primitives as you want inside. The next two weeks I want to flip things. I want to show you several CSS filter-functions that are all shortcuts for one of two primitives.

Next week we’ll look at four functions that are all shortcuts to different effects that the feColorMatrix primitive can produce and the week after I’ll show you four more functions that are shortcuts for the feComponentTransfer primitive.

Download a free sample from my book, Design Fundamentals.

Leave a Reply

Your email address will not be published. Required fields are marked *