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 Chrome, Firefox and Safari.  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.

.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));
	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-images, 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.