CSS Drop Shadows

They’re the corkscrew in every graphic designer’s Swiss Army knife. Much used, oft maligned but always popular, drop shadows are a staple of graphic design. Although easy to accomplish with image-editing software, they’re not of much use in the fast-changing world of web design. On the web, adaptability and ease of use dictate trends — and static images with a fixed background effect are not very adaptable.

Article Continues Below

But what if we had a technique to build flexible CSS drop shadows that can be applied to arbitrary block elements? That can expand as the content of the block changes shape? Compatible with most modern browsers? With better results for standards-compliant browsers? If you’re not sold yet, we can also tell you that it requires minimal markup.

Interested? Well, first off, we wouldn’t want to take credit for something we didn’t invent, but merely improved upon. This particular technique was conceived and demonstrated by Dunstan Orchard, of 1976 design fame (hats off to you, Dunstan). We found it was easy, intuitive, and worked like a charm. However, after closer examination, we saw room for improvement and set to work on it.

Here’s how it works: you need to make a drop shadow image in the image editor of your choice. It should be only the shadow, without a visible border (an easy way to do this is by applying the effect to an empty selection). Make sure your image is big enough to cover the maximum expected size of the block elements that will use it. In practice, we’ve found that 800 x 800 is a respectable enough size. Save it as a GIF, making sure you use the color of the background you’ll apply the effect over. Additionally, save the same shadow with full alpha transparency (no background color) as PNG. This will be used to feed a better shadow to browsers capable of displaying it. These are some sample files: GIF file/PNG file.

test

We’ll start by giving a shadow to an image and then move on to other block elements. In a moment of ingenuity, we decided to name our class “img-shadow”. Our test subject shall be this cute cat:

And its corresponding markup (one div is the only extra markup we’ll need):


<div class="img-shadow">
  <img src="cat.jpg" alt="test"/>
</div>

The following illustration shows how the technique works:

Technique illustration


First, our previously prepared shadow file will be set as background for the div.

background: url(shadow.gif) no-repeat bottom right;

Then we’ll give the image negative top and left margins to make the “drop” that gives us the shadow. Our shadow is six pixels wide, so that’s our magic value.

margin: -6px 6px 6px -6px;

We float the div to avoid having to specify its size (otherwise it will take up all available horizontal space).

Remember we said that we’d provide better shadows for better browsers? This line will do the trick:

background: url(shadowAlpha.png) no-repeat right bottom !important;

That “!important” bit tells the browser that the declaration is to take precedence over normal declarations for the same element (see the spec). It also happens to be unsupported in all versions of Internet Explorer, which also lack native support for transparent PNG’s. It’s almost too convenient. By specifying controversial declarations twice, we get the desired behavior (IE takes the second one, most other browsers the first one). The end result is that, were the background color to change, browsers that support PNG would maintain a perfectly transparent shadow. Sadly, Explorer’s shadow will stay with its original background color.

But why do this you ask? The reasons are twofold:

  • We can: This is a painless, effortless and automatic hack that yields great results in the browsers that support it.
  • It may fix itself: If the new version of Internet Explorer (shipping with Longhorn) supports both of these standards, we won’t have to fix a thing to get pixel-perfect, truly transparent shadows in it.

The finished CSS code looks like this:


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

.img-shadow img {
  display: block;
  position: relative;
  background-color: #fff;
  border: 1px solid #a9a9a9;
  margin: -6px 6px 6px -6px;
  padding: 4px;
  }

Differences in margin size account for IE’s box model, and that last padding value gives us a nice frame around the image. Sadly, it is lost in IE 5.5 and 5.0. The drop shadow effect stays, though.

Our shadow will blend seamlessly with its background in standards-compliant browsers. In Explorer, the shadow will clash with the background unless you’ve stuck with the background color you used for your shadow. You can see the results here:

A cute cat
A cute cat

For the next part, we’ll apply the drop shadow effect to a paragraph.

Logic dictates that the same technique should yield similar results when working with a paragraph, which can be treated as another block element. And indeed, with most browsers, it works like a charm. Care to guess which one doesn’t get it right?

While developing this technique, we found that when working with a block element other than an image, in bold defiance of common sense, Explorer decided to clip the left and top parts of the block — the ones that “jump” out of the shadow — regardless of what we tried. Amusingly enough, the only version of Explorer that gets this right is 5.0. No amount of hacks, overflow settings, or gentle suggestions seemed to help (and yes, righteous cursing was tried). We gave up and decided that a different approach was called for.

The method we came up with is partly based on Douglas Bowman’s Sliding Doors methodology, and calls for an extra bit of markup (another div), so our paragraph will look like this:


<div class="p-shadow">
  <div>
    <p>The rain in Spain ...</p>
  </div>
</div>

Instead of giving the paragraph negative top and left margins, we’ll give it positive right and bottom padding. This will expose the shadow (set as background for the outermost div). Then we’ll fake the shadow offset by using a partly transparent GIF as background for the inner div, which will overlap the shadow. Make sure that the visible part of this image is the same color as the background over which you use the drop shadow effect. Name the image “shadow2.gif”. It should be constructed as follows:

Fake offset image example


Here’s an example GIF file (this image will most likely look as white on white on your browser, so you may want to save it and take a look at it in your image editing program).

This illustration shows what we’re going to do:

Paragraph technique illustration


The following are the styles needed to accomplish the effect. Notice that the extraneous image and padding are used only by Internet Explorer. Most other browers effectively ignore the inner div, and stick with the method we used for the drop shadow of the image.


.p-shadow {
  width: 90%;
  float:left;
  background: url(shadowAlpha.png) no-repeat bottom right !important;
  background: url(shadow.gif) no-repeat bottom right;
  margin: 10px 0 0 10px !important;
  margin: 10px 0 0 5px;
  }

.p-shadow div {
  background: none !important;
  background: url(shadow2.gif) no-repeat left top;
  padding: 0 !important;
  padding: 0 6px 6px 0;
  }

.p-shadow p {
  color: #777;
  background-color: #fff;
  font: italic 1em georgia, serif;
  border: 1px solid #a9a9a9;
  padding: 4px;
  margin: -6px 6px 6px -6px !important;
  margin: 0;
  }

The same considerations for background color mentioned in the image example apply for paragraphs. Here’s the end result. (Try resizing the text on your browser to see the box change size and watch the shadow adjust.)

The rain in Spain falls mainly on the plain.



Additional notes

In this article, the styles for image and paragraph have been broken up for clarity, but both could be specified in one fell swoop with minor adjustments.

This technique has been tested with Gecko-based browsers, Safari, Opera and IE 5.0+. Apart from the differences noted, no problems were observed. It should work well with most of the stuff out there (no, not Netscape 4.x).

Acknowledgements

To Dunstan for inventing the drop shadow techique and Douglas Bowman for the Sliding Doors technique

About the Author

Sergio Villarreal

Sergio Villarreal lives in México but spends most of the time in his head. He maintains a weblog and rarely updated webcomic at Overcaffeinated.net and makes a point of learning a new trick every day. Some are even useful.

82 Reader Comments

  1. I know I keep nudging the conversation off-topic, but I just can’t resist! The issues surrounding visual techniques such as this cut across mediums, from print to web to animation and video.
    If only drop shadows were as easy as this Flash Actionscript class: http://www.quasimondo.com/archives/000184.php
    Saved my bacon on a Flash presentation with a bunch of dynamically loaded (and variable-sized) images.
    Play with the sliders (above), and dream of CSS3…

  2. David House wrote:
    > Floats need an explicit width.
    >
    > “We float the div to avoid having to specify
    > its size (otherwise it will take up all
    > available horizontal space).”
    >
    > Tut tut, this is a hack.

    The current method of setting a float on a box, but not setting an explicit width, so that the box is rendered only as wide as its contents may be incorrect at the moment (although it passes CSS validation) but that will change very soon.

    As all modern browsers, except IE5/Mac & Opera, render this CSS as desired, the W3C has responded by modifying the float requirement in CSS 2.1 (currently a Candidate Recommendation, implying it will be a full Recommendation imminently).

    CSS 2.1 effectively says that providing you set width:auto when floating a box, your CSS is valid and boxes can be rendered as wide as their content (‘shrink-to-fit’) – the desired behaviour.

    http://www.w3.org/TR/2004/CR-CSS21-20040225/visudet.html#q8

    The W3C should be applauded for making this concession/acknowledgement of how real-life designers use CSS.

  3. Great technique and article, Sergio!

    However, I found one flaw in the technique that I wasn’t able to fix. Namely, the drop shadow breaks when the photo is centered in a table cell (e.g. in a photo album index page), unless all the photos in the same column are of exactly the same width.

    The shadow gets ok if I put another div around the img-shadow div, but then the image is not centered in the cell anymore.

    OK, OK, I know I shouldn’t maybe use tables, but for grids like this I’ve yet to find any better way. Besides, even when trying to use only div’s for the layout I still couldn’t center the image nicely in the surrounding div.

    Could someone please give me a hint how to center the shadowed image inside another element without breaking anything?

    TIA,
    Jarkko

  4. I’ve got strange problem. Msie 6 does not display http://www.jpd.sk/ page after load, you have to move mouse over top menu to show contents. Other pages on this site uses the same css and page structure, but displays ok. Suggestions?

  5. Great article and technique, thanks Sergio. I tried it on my pages and it worked great, except in IE6/XP. After a lot of pissing around with test cases I discovered that if the page has an xml declaration at the top ie: , then the “padding: 4px;” at the end of the “.img-shadow img” style rule is ignored. Everything works except the image has no padding inside the frame. Wierd. I assume this has something to do with IE’s quirks mode. Anyone else seen this?

  6. Dunc: I ran into the same problem while writing the article. Specifying an XHTML transitional doctype makes IE6 display the padding correctly. Other doctypes result in the behavior you get in IE5 and IE5.5 (padding applied to image elements doesn’t show). I’d assume that XHTML 1.0 transitional and up would work.

  7. I wonder whose fault that is…

    When IE6 goes into Strict Modes it uses the W3C Model. Since this box model makes no sense, stick to Quirks Mode.

    Need I say more?

  8. I don’t think that has anything to do with it, Dante, or other browsers that implement the Box Model as per the w3c standard wouldn’t show the padding. I think it’s Quirks mode itself that causes Explorer to dismiss the padding.

  9. Why use an image? Just create a box with gray bg. Image is only useful when the shadow is to be blurred (which normally seems to be the case).

    But if we put shadow-image with blurred shadow, it will break-up into pixels if we write a 40 line paragraph for instance!

  10. It seems to me that the extra PNG is useless. I don’t want IE to have ugly shadows, where the background colors clash. I want my site to look good in all of todays browsers.

    Sure, going past IE is great, but not in this case. I can’t tolerate the ugly drop shadows on my site. I think I’ll just learn what my background color is and adjust the shadow to that color for now…

  11. sergio,

    thanks for your great article. i am now implementing this drop technique on a site i’m building for a friend — works great in ie5.x/6win ns7win and safari, but not so in mac ie 5.2. not sure why. the div and the image disappear above the view port (you can barely make out the drop .gif along the top).

    see an example here: http://www.lesliebrothers.biz/

    here’s the html:

  12. Sergio,

    Great article. Of course I went to try it out and it works fabulously. I have an image in the

  13. Andy: when a block element is created, by default it assumes all available horizontal space. That is what you’re seeing (with the shadow going all the way to the right). The float, in this case, is very necessary. The element can be floated to left or right, it doesn’t matter, but it *does* have to be floated. Thus, positioning of the image must be done through fiddlement of the margin values.

    If you want to center the image you’ll have to enclose it in another div and center that.

    I’m working on some improvements of the technique, so there may be more to talk about later =)

  14. Sergio,

    Thanks for the reply. I took out the style=”float:none;” from the div and wrapped the img-shadow div like so.

    And the image does not center. It floats to the left. Am I not centering the enclosing div properly?

    I look forward to improvements in the drop shadow technique because it’s great.

    Andy

  15. Sergio,

    You’re my hero. Andy Budd’s page worked. It only took me 30 min to figure it out though. I added 2 divs around the object to be centered with the following css

    .centerWrap
    {
    min-width: 400px;
    text-align: center;
    }

    .center
    {
    margin: 0 auto;
    text-align: left;
    width: 250px;
    }

    Andy’s width of 600px didn’t seem to center the image for me but using a smaller width of 250px and a min width depending upon how narrow you’re willing to let your browser window collapse seems to work great.

    Thanks. Now can’t there be a simpler way?

    The only problem I see is in Camino 0.7 I loose part of the drop shadow. 🙁

    Andy

  16. I really think you guys are doing a great job coming up with solutions in CSS.

    I really which that CSS actually separated content from presentation though. If CSS really worked than all you should need in the HTML is

    Anything more just shows that CSS needs another iteration or two before it really delivers the promise of separating content from presentation.

    To take it even further, if CSS really worked then using only image tags all with the same class you could be able to format a gallery as in









    and have that show up in any format you want. 9 images vertically, 3 by 3, some other format including all the styles in iPhoto all only by changing the CSS.

    Who do we have to influence to get this thing done right?

  17. hello everyone…

    i’ve tested this script. it works fine when its in the tag.

    but when its within another

    tag.. it looks very weird!

    anyone experienced this before?

    cheers,

    vincent

  18. For those Safari users, once you update your OS to 10.3.4 (which brings Safari 1.2.2 I guess, or at least updates it), you will notice that your dropshadows (using the technique in this article) are aligned all the way left, so there’s no right-side shadow and it cuts off with the picture edge on the left.

    Anybody have a quick fix for this? Is it a problem with Safari’s CSS rendering? It still works in other Mac browsers (IE, NS). Should I submit a report to Apple?

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career