summaryrefslogtreecommitdiff
path: root/old/published/Webmonkey/css-dropshadows.txt
blob: fcf4e35cbd5408813e5a60c875097e7a7b480c50 (plain)
1
Drop shadows, love 'em or hate 'em they're a reality for most web designers. Luckily adding drop shadows to most elements on a web page isn't too difficult. The most common trick is to use an oversized shadow image and apply that as a background to a wrapper tag.

Yes, that's right, drop shadows will require a little bit of non-semantic markup, if that bothers you then drop shadows aren't for you. If you're okay with a few wrapper tags, then read on and we'll show you how it's done.

== Wrapping an image ==

The most common use of drop shadows seems to be images. The shadow helps set images apart from the page much the way a frame helps do the same on a wall (the first person who says it makes the image "really pop" will be slapped).

To create a drop shadow that can be applied to every image on your site you need to create a shadow image that's bigger than the largest image you'll apply it to. For most situations an 800 pixel square image should do the trick, though if you're sure you can get by with something smaller, definitely do so since this image will slow down page loads.

So how do you make the image? There are a number of ways you can do it, depending on your image editor. Our favorite is to simply create a new 800 pixel image and simple make an empty selection on top the background and apply a shadow to it. Adjust the light angle and spread to your liking and save the image as shadow.png For this browsers that can't handle .png files with transperancy files we'll need a second image. This time make the background layer the same color as that of your site and save the file as shadow.gif.

The HTML markup can take a variety of forms but here's a fairly common method:

<pre>
<div class="shadow">
    <img class="shadowed" src="/mygreatimage.jpg" alt="my great image" />
</div>
</pre>

The last step is bringing it all together with some CSS rules. Here's the code:

<pre>
.shadow {
    float:left;
    background: url(/path/to/shadow.png) no-repeat bottom right;
}
.shadowed {
    display: block;
    position: relative;
    background-color: #fff;
    margin: -6px 6px 6px -6px;
}
</pre>

So what's going on here? Well, first off we apply a float to our container element so that the background won't span the whole width of whatever our <code>.shadow</code> div's parent may be. Then we apply the image as the background.

So far so good, but our shadow graphic is hidden by the actual photo so what we need to do is shift the photo a bit. But first we make sure the photo is displayed as a block element and is positioned relative to its parent (the <code>.shadow</code> div). Then we simply add negative margins to the top and left sides of the photo. This has the effect of pulling the image back to reveal the shadow beneath it.

Awesome. We have a drop shadow. unless of course you're using IE, which wouldn't know a transparent .png file from Bill Gate's underwear and chokes on both. To fix that we'll use the ever-popular (and proprietary) [http://msdn.microsoft.com/en-us/library/ms532969.aspx AlphaImageLoader Filter].

So, in a separate stylesheet that only gets served to IE (conditional comments are your IE friend), we need to add this line:

<pre>
.shadow {
    filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/shadow2.png',sizingMethod='crop');
  background: none;
</pre>

And there you have it, a drop shadow for your images. Now the very obsessive among us may be bothered by the fact that the left and top edges of our shadow are "hard," that is, they don't gracefully fade in on the edge where they begin.

There is a way to fix that, though we think it's more work than it's worth. However, if you're incredibly anal-retentive about your shadows, it is possible to get soft edges.

This trick comes from an old [http://alistapart.com/articles/cssdrop2/ A List Apart tutorial] and requires yet another container div so that the HTML would look like this:

<pre>
<div class="shadow">
    <div>
       <img class="shadowed" src="/mygreatimage.jpg" alt="my great image" />
    </div>
</div>
</pre>

Now what we need to do is create a reverse shadow, that is an image that's the same color as the page background, but fades inward from 100 opacity to 0. once you have that image, just apply it as a background to the inner div tag. That way it overlays the shadow and softens the left and top edges for a more realistic shadow effect. See the ALA post for all the details.

The above technique will work just fine on basically any element in most browsers (so if you want drop shadows on say a colored div, just use the wrapper tags. 

Okay, so we have a way to put drop shadows on our big blocks of content, but what if you want to drop shadow some text?

== Drop Shadow Text ==

If you've ever used Apple's Safari web browser you may have noticed some sites have drop shadowed text. Safari is about the only browser that supports the <code>text-shadow</code> CSS rule (though Firefox 3.1 will support it as well).

The question is, can we mimic the <code>text-shadow</code> effect across all browsers? The answer is sort of. Most of them don't render quite a nicely as Safari, but it is possible to get at least some sort of shadow.

Obviously, for Safari we just need to add the text-shadow rule like this:

<pre>
p.shadowed { text-shadow: #999 5px 5px 5px; }
</pre>

It turns out that Internet Explorer has it's own proprietary method of adding shadows, so fire up those conditional comment stylesheets and add this line:

<pre>
p.shadowed {
	height: 1em;
	filter: Shadow(Color=#999, Direction=135, Strength=5);
}
</pre>

What about Firefox and Gecko-based browsers? Well, there is a way to do it, however it's ugly and it kills accessibility since it repeats your text. In fact, we recommend skipping this one and just waiting for Firefox 3.1 to support <code>text-shadow</code>. But if you just can't be dissuaded, here's what you need to do:

<pre>
p.shadowed {
  line-height: 1em;
  white-space: nowrap;
  
}

p.shadowed:before {
  display: block;
  margin: 0 0 2px 2px;
  color: #999; 
}
p#shadowed_text:before { content: 'Look, ma, Shadows!'; }
</pre>

The key here is the <code>:before</code> pseudo-element which causes Firefox to take whatever text is in the element and duplicate it, offset to the right and down a little bit. It will also automatically be set to light gray, though I've explicitly set it to match our other efforts.

The only thing we need to do is give our paragraph an id of <code>#shadowed_text</code> and then set the content to match whatever is in the p tag.

The problem this introduces is that Safari also understands the <code>:before</code> rule (naturally IE does not) so Safari applies the text shadow ''and'' the <code>:before</code> hack which ends up looking strange.

Designer Neil Crosby, who came up with the this technique, uses the [http://www.giantisland.com/Resources/LitePacificHackforSafariAndIE7.aspx Stokely Safari Hack] to hide the <code>:before</code> element. The hack is somewhat complex and we recommend reading up on it at the link above and also check out [http://www.workingwith.me.uk/articles/css/cross-browser-drop-shadows how Crosby uses it in his guide].

So, ugly hacks all, we have some cross browser text shadows.

== Conclusion ==

If you've made it this far you're clearly a drop shadow obsessive and you'll be happy to know that there is some light on the horizon. Drop shadows using pure CSS have been theoretically possible since the CSS 2.1 spec was adopted. Unfortunately browsers have been slow to adopt support for it, but that appears to slowly changing.

There's also some hopein the form of the CSS 3 spec. As we saw above Safari and Firefox 3.1 support the text-shadow element and both also support the <code>box-shadow</code> element which is set to arrive in CSS 3. The <code>box-shadow</code> rule makes adding a shadow to an element as simple as this (which would work in Safari):

<pre>
-webkit-box-shadow: 2px 2px 2px #999;
</pre>]

Sounds pretty good after wrestling with background images and pseudo elements doesn't it? Just don't hold your breath waiting for IE 8 to catch up.