Comparison of drop-shadow filter (left) to box-shadow property (right) on a 16-bit alpha-masked PNG image

There’s been a lot of talk over the differences between the CSS box-shadow property and the drop-shadow filter. The former has been around for a long time, and is well-supported across modern browsers; the latter is a translation from SVG into CSS, and currently has support in all modern browsers, with the exception of IE.  At first glance the CSS and filter shadow techniques appear to be same effect: even their syntaxes are very similar. As we’ll see, there are some very significant differences between the two.

I’ll be contrasting the two methods by applying them to the same element using two different classes:

.shadowCSS {
	box-shadow: 12px 12px 7px rgba(0,0,0,0.5);
.shadowfilter {
	-webkit-filter: drop-shadow(12px 12px 7px rgba(0,0,0,0.5));
	drop-shadow(12px 12px 7px rgba(0,0,0,0.5));
	filter: url(shadow.svg#drop-shadow);

Much of the recent conversation has focused on one feature or another; this article will be a complete side-by-side matchup of the two systems, comparing flexibility, rendering speed and quality. Vendor prefixes have been removed for clarity.

Photograph of a woman in a cat mask
border-image:url(gold-picture-frame.png) 81 83 82 84;
border-width: 60px;
filter: drop-shadow(9px 9px 9px rgba(0,0,0,0.3));
filter: url(shadow.svg#drop-shadow);

The most exciting part of filter shadows is that they follow the explicit outline of elements. That’s even true for 32 and 16-bit PNG’s, as you can see above. box-shadow (as the name implies) reflects the rectangular shape of the image, ignoring the alpha mask; filter shadow follows the mask outline of the PNG.

That also includes border-image, provided the border-image is an alpha-masked PNG.

The drop-shadow filter takes into account the addition of pseudo-elements, such as :before and :after, as in these pure-CSS speech-bubbles: note the shadow underneath the triangle in the filtered version.

“A girl’s gotta eat.”

filter: drop-shadow(9px 9px 9px rgba(0,0,0,0.3)); 
filter: url(shadow.svg#drop-shadow);

“It’s such a waste when pretty things get broken.”

box-shadow: 9px 9px 7px rgba(0,0,0,0.3);

Limitations of the drop-shadow filter

A few drawbacks of the filter approach should be noted at this point:

  • The dropshadow filter should support a fourth spread value to swell the shadow just as box-shadow does, but it appears that the current implementation in Webkit will consider a fourth value a parsing error and turn off the shadow entirely in response.
  • The filter spec does not support an inset value, so you can't easily create inner shadows with filter code.

Further differences

Both shadow effects respect border-radius and transform, but the filtered shadow will appear “under” an element with no background, whereas box-shadow will treat it as solid. If the border is irregular (dashed, for example), the filter will honor that; box-shadow will not.

border: 3px solid #262b57; 
width: 150px; height:150px;
border-radius: 10px;
transform: rotate(8deg);
box-shadow: 9px 9px 7px rgba(0,0,0,0.3);
filter: drop-shadow(9px 9px 9px rgba(0,0,0,0.3));
filter: url(shadow.svg#drop-shadow);
border: 3px dashed #262b57;
box-shadow: 9px 9px 7px rgba(0,0,0,0.3);
filter: drop-shadow(9px 9px 9px rgba(0,0,0,0.3));
filter: url(shadow.svg#drop-shadow);

Because it is only shadowing the border (which is just four pixels thick in this case) the filter version appears lighter.


filter(box-shadow) is definitely the winner in this round: it has far greater flexibility, and only loses when it comes to inset shadows and (current) lack of spread.

Speed & Quality

While the rendering quality appears much the same between the two systems, drop-shadow filters have the advantage of hardware acceleration if the browser vendor supports it; box-shadow does not have access to that code. All other factors being equal, the drop-shadow filter will tend to render faster.


So which do you use? At this stage I think we can set a few simple rules:

  1. if your element is solid and has a solid border (with or without border-radius), use box-shadow. It has better support, and will provide the same visual result as the drop-shadow filter, albeit a few milliseconds slower.
  2. If you want an inset shadow – for example, to achieve a vignette effect – use box-shadow.

If you have a PNG image with an alpha mask, there are several options:

  1. Bake in the shadow using or your image editor of choice, so that every browser sees it the same way;
  2. Leave the image unaltered and use the drop-shadow filter, knowing that only Webkit browsers will see the shadow for now.
  3. Try to use an SVG drop-shadow filter on the content for equivalency in other browsers.

If your element has an irregular outline that’s not controlled by border-radius - why not take advantage of CSS fallback techniques and use both?

“Show a man what he expects to see, and he won’t look beneath the surface.”

One cautionary note is that both shadow render systems will be active with this CSS: Webkit will “double up” the shadow on the regular element. However, you will achieve fallback support in older browsers that only have box-shadow.

I’m also going to place a bet that the filter version will be open to manipulation by CSS Custom Filters… which will be great for doing curved drop-shadows without any need for trickery.

As you can see, the two systems are very different, and appropriately named: hopefully this comparison can be a metric for you to decide how to use either in your future projects.

Photograph provided by Stefano Corso under Creative Commons; Catwoman illustration by Aria Lance.

Enjoy this piece? I invite you to follow me at to learn more.