There’s been a lot of talk over the last few days over the differences between the CSS3 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 only has support in recent Webkit-based applications, or in Firefox through an equivalent SVG filter. 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. You will need a recent Webkit browser (Safari 6+, Chrome 18+) or Firefox to see the filter version.
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, as shown in the photograph above (provided by Stefano Corso under Creative Commons), 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
dropshadowfilter should support a fourthspreadvalue to swell the shadow just asbox-shadowdoes, 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
insetvalue, 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-shadowfilter, albeit a few milliseconds slower.If you want an
insetshadow – 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-shadowfilter, 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 (an option that will be explored in the very next article).
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 CSS3 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.
*Although I should point out that Lea Verou was, as ever, on top of this subject almost a year ago.