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.
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 “A girl’s gotta eat.” “It’s such a waste when pretty things get broken.”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.
filter: drop-shadow(9px 9px 9px rgba(0,0,0,0.3));
filter: url(shadow.svg#drop-shadow);
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 fourthspread
value to swell the shadow just asbox-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.
Judgement
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.
Conclusion
So which do you use? At this stage I think we can set a few simple rules:
- if your element is solid and has a solid border (with or without
border-radius
), usebox-shadow
. It has better support, and will provide the same visual result as thedrop-shadow
filter, albeit a few milliseconds slower. - If you want an
inset
shadow – for example, to achieve a vignette effect – usebox-shadow
.
If you have a PNG image with an alpha mask, there are several options:
- Bake in the shadow using Photoshop or your image editor of choice, so that every browser sees it the same way;
- Leave the image unaltered and use the
drop-shadow
filter, knowing that only Webkit browsers will see the shadow for now. - 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 twitter.com/dudleystorey to learn more.