A List Apart

Menu
Issue № 178

CSS Drop Shadows II: Fuzzy Shadows

by Published in Browsers, CSS, Graphic Design80 Comments

We like shadows. We enjoy making them drop and we love CSS and standards, so we wrote CSS Drop Shadows. The little voice in our head approved of it. We thought that was the end of it.

We thought wrong.

The internet being the kind of medium it is, minutes after the publication of the article, we started receiving comments, queries and suggestions for improvements. Most notable among the latter was Phil Baines’ method for keeping the markup simple when dealing with paragraph drop shadows. We are indebted to him.

The most complained-about shortcoming of the technique turned out to be the sharp top and left edges of the shadow, which, although generally acceptable, are unlike what an image editing program would produce (a fuzzy shadow). Given that the shadow image is effectively clipped at those points, we felt this was an unavoidable inconvenience, chiefly due to Internet Explorer’s inability to display PNG’s transparency natively.

A cat's nose


A cat's nose




blowup of shadow detail


Then Jan pointed out a technique for making Internet Explorer render PNG’s alpha channel correctly. It works by activating Explorer’s AlphaImageLoader filter (previously discussed in this ALA article), but does so in an inobtrusive way which requires no extra javascript code. We think it’s a godsend. Combining this technique, some image trickery and our “fake shadow offset” method, we’ll be able to make properly fuzzy shadows that work across browsers.

In this article we’ll learn how to:

     
  • Hide a stylesheet from non-IE browsers so it doesn’t affect document validation.
  •  
  • Coerce IE5.5/IE6 into displaying PNG transparency correctly.
  •  
  • Use the above to create fuzzy shadow edges for our Drop Shadow effect.

First, we’ll fabricate our fuzzy shadow edge. To do this, we must create an inverse shadow in our image editing program. Usually we’d use a black shadow over a background color. For this effect, we’ll need a colored shadow. It must be the same color as the background over which we’ll apply the effect.

Start with an image like the “fake shadow offset” we described in the previous article. This one should be thinner than before (about 3px thickness for a 6px shadow has worked out well for us). Our examples will use white as background color. When reproducing this technique, adjust for yours.

We’ll apply a “Drop Shadow” effect to this image, taking care to specify white for the shadow color. A strong shadow is desirable — the stronger it is, the faster your shadow will seem to fade. We should now have something that looks like this:

Fake Shadow offset image


Save this image as a PNG with full transparency. We’ll use this file for IE5.5, IE6 and standards compliant browsers. Make a regular version sans shadow with thicker offset (as seen in the previous article) and save that as a GIF file. We’ll feed this one to IE 5 (which does not support the AlphaImageLoader filter). Here are sample files for your perusal: PNG/GIF (Check them on an image editing program, since they will look like white on white in your browser).

Since we now have a solid color at the edge of our offset, we’ve effectively given up on the possibility of having a transparent shadow, so we’ll use a simple GIF for it. Make sure you apply the effect over the background color you’ll use. Here’s our example shadow: GIF.

The markup for this effect will be two <div>’s around our image/block element.

<div class="alpha-shadow">
  <div>
    <img src="img/test.jpg" alt="just a test" />
  </div>
</div>

The basic technique is still the same: We’ll set up the fake offset (with its inverse shadow) as background of the innermost <div>, and the shadow as background of the outermost one. When overlapped, the transparency of the PNG will seem to gradually dissolve the shadow image until it becomes the solid background color. The tricky part is making this work in Explorer.

Illustrated process


Our CSS is pretty much what we had seen in the previous article:

.alpha-shadow {
  float: left;
  background: url(img/shadow1.gif) »
  no-repeat bottom right;
  margin: 10px 0 0 10px !important;
  margin: 10px 0 0 5px;
}

.alpha-shadow div {
  background: url(img/shadow2.png) »
  no-repeat left top !important;
  background: url(img/shadow2.gif) »
  no-repeat left top;
  padding: 0px 5px 5px 0px;
}

.alpha-shadow img {
  background-color: #fff;
  border: 1px solid #a9a9a9;

  padding: 4px;
}

If you look closely you’ll notice we’re still including the non-fuzzy GIF offset (shadow2.gif) as background of the inner <div>. This is for the benefit of Internet Explorer 5.0, which doesn’t support the AlphaImageLoader filter. As it stands, this code will apply to all versions of Explorer. To make adjustments for IE 5.5/6, we’ll create an extra CSS file.

ie.css

To activate the AlphaImageLoader filter in a simple and reliable way, we’ll first include it in its own CSS file and name it ie.css. We know this is shameful and will probably make the Standards Squad put a price on our head, but we’ll hide this file from other browsers later, so it’s ok. Kind of.

Our ie.css stylesheet will look like this:

.alpha-shadow div {
  filter:progid:DXImageTransform.Microsoft»
.AlphaImageLoader(src='img/shadow2.png', »
  sizingMethod='crop');
  background: none;
}

The AlphaImageLoader filter supports two sizing methods: crop and scale. We’ll use crop for our offset (scale fits the full image into the block, and is not what we’re looking for). Since the filter is somewhat limited and does not support CSS-like image positioning, we’re stuck with shadows that drop down and to the right (the image on its default position is all the way to the left and top).

We should note that, since the filter places the image in the foreground of the block element rather than as its background, this technique could be set up to show fuzzy shadows in Explorer with only one <div> surrounding the image, and show the hard edge shadow for other browsers. Not being ones to reward bad browser behavior, we’ll stick to the technique with the extra <div>, which gives us a fuzzy shadow in almost every browser under the sun.

The second line, where we set the <div>’s background to none, is there in order to remove the GIF offset we specified in the CSS before. Since we’ll only feed this file to IE5.5 and IE6, IE5 keeps the GIF offset (and thus displays a hard edge shadow). The rest of the browsers ignore that GIF file by the !important method we specified in the previous article.

Conditional Comments

To hide the ie.css stylesheet from all browsers that don’t need it, we’ll use Conditional Comments, a Microsoft provided technique to serve content to specific versions of Internet Explorer. They are included in the html document and look like standard html comments, so browsers other than IE5+ ignore them (and so does the w3c Validator, which is convenient). We’ll insert this in the <head> of our document, after the CSS for the drop shadow:

<!--[if gte ie 5.5000]>
<link
  rel="stylesheet"
  type="text/css"
  href="ie.css"
/>
<![endif]-->

What that does is specify that the enclosed bit of code should be used by versions Greater Than or Equal (the gte part) to Internet Explorer 5.5 (it must be specified as 5.5000 because of Version Vectors), thus feeding IE5.5 and IE6 the special stylesheet.

That completes the technique. This may seem overly complicated just to achieve a fuzzy shadow, but then again, they say that God is in the details. As a plus, the mentioned techniques can be used to achieve all sorts of different effects.

Here, have a cat:

Cat on floor



Acknowledgements

To Jan, who has been playing with this transparency thing for far longer than we have, to Phil Baines, for his suggestions on how to improve the methods exposed in the previous article, and to Ava McBride, for facilitating the use of the Browsercam service for testing of these techniques.

About the Author

80 Reader Comments

Load Comments