The Shape of Days

A whimsical assortment of things that totally jack my shit


Blog

Friday, December 2, 2005, 2:42 pm

An improved CSS shadow technique

Remember this? I was playing with ways to apply shadows to images using CSS the other night, and I wrote a little description of a technique I’d worked out. It was fairly well received by people who care about such things. One of those people sent me an e-mail in which he suggested that I might be able to use JavaScript to streamline the technique. I allowed that it sounded plausible, but that I didn’t have the expertise to know for sure and that I lacked the time at the moment to dig into it.

Well, this morning I had the time. With some help from my de facto collaborator, I was able to come up with what seems to be — seems to be, I said — a very robust and easy-to-use technique for applying snazzy looking shadows using only Web technology and a few little image elements prepared beforehand.


The biggest single complaint I got from people who read my article involved the complexity of the markup required to make the technique work. In HTML, an image looks like this:

<img src="http://example.com/prettygirl.jpg">

My technique required the designer to change that to this:

<div class="shadow">
  <img src="http://example.com/prettygirl.jpg">
  <div class="topleft"></div>
  <div class="topright"></div>
  <div class="bottomleft"></div>
  <div class="bottomright"></div>
</div>

Definitely not an improvement. As I observed in my article, this is still light years ahead of the nightmare that was table-based page layout, but that’s just damning with faint praise. All that extra markup sucks out loud.

The new-and-improved technique will apply a snazzy white matte and drop shadow to any image without all the ugly extra markup. Instead of that seven-line beast, you can just write this:

<img class="shadow" src="http://example.com/prettygirl.jpg">

And if you’re clever with your JavaScript, you can even omit the class declaration for images you want shadowed, and use something like class="noshadow" only on the images you don’t want shadowed. That leaves the markup for your shadowed images looking like this:

<img src="http://example.com/prettygirl.jpg">

Look familiar? Either way you go, the principle’s the same; either have your JavaScript look for a special class of images to apply shadows to, or have your JavaScript apply shadows to all images except those in a special class. Tomayto, tomahto.

Here’s how it looks:

Pretty girl

Better, yes?


Now, despite how it looks, we are not applying the shadow with CSS. We’re using using the class attribute as a marker that our script can use to find the images we want shadowed. The shadow class on img elements isn’t even included in our style sheet. It does nothing at all by itself.

The script works like this: It starts by getting a list of all the img elements included in the document. Then it looks at each of them in turn to see if there are any that need shadows. If an img does not belong to the shadow class, the script ignores it and moves on. But if it does belong to the shadow class, the script does some things. Clever things.

Let’s talk about the Document Object Model for a second. Web pages — any XML-like content, actually — are structured like an outline. There are top-level things and then second-level things and so on. A very simple Web page, structurally, looks like this:

  1. An improved CSS shadow technique
    1. Introduction
      1. Open with a joke
      2. Mention viewer mail
    2. Description of the old technique
      1. Big ugly markup
      2. The markup is big
      3. The markup is also ugly
    3. Improvements made
      1. Now uses JavaScript
      2. Markup no longer big, ugly
      3. Also solved floating box problem
      4. Picture of pretty girl
    4. Conclusion
      1. I am so totally cool
      2. Send me all your money

The Document Object Model considers Web pages in terms of nodes and children. For example, in the little notional outline above, number 2 under Roman numeral I, “Description of the old technique,” is a node and points 2a, 2b and 2c are its children. But apart from just giving us an annoying new vocabulary to learn, the DOM provides a programming interface by which we can examine the structure of a Web page through JavaScript, and — and this is the key — change it.


Using the first iteration of my technique, the person creating the Web page — you know, me — would have to look through his page and find any instances of img elements that need shadows behind them, write some new HTML code to describe the divs the shadow technique requires, and then cut-and-paste the existing img tag into the new div container. It would have been a tedious and repetitive operation even under the best of circumstances.

But every public-school-educated child knows that in 1689 New England religious scholar Cotton Mather, with the help of his best friends Einstein and Hammurabi, invented the digital computer specifically to relieve man of the burden of performing tedious and repetitive operations. Perhaps we can make use of that invention somehow …


In point of fact, it’s fairly easy to write a JavaScript that does exactly what I described in exactly the way I described it. I’m using one on this site right now — it’s how the shadowed picture of the pretty girl a few paragraphs up came to be — and I’ve prepared a detailed, documented example for anybody who’s interested. But in principle, it works exactly the way I described. The script goes though the page’s DOM tree from top to bottom looking for img elements. When it finds one, it examines it to see if it belongs to the shadow class. If it does, the script creates a new DOM node of type div and assigns it to class shadow. Then it makes a copy of the img element and attaches it to the div node as a child. It then populates the div node with the rest of the elements required to make the shadow look right. Finally, the script replaces the img node with the new div node. Piece of cake.

An incidental benefit to this new approach is that I was able to solve the floating box issue. People who live deep inside their Web browsers will know what I’m talking about when I refer to the collapsing-box problem; it’s a classic one for Web designers. It really annoyed me when I was working on this technique, and my solution to it last time around was not at all to my satisfaction. But the JavaScript approach lets me solve the problem much more elegantly.

In a nutshell, the collapsing-box problem goes like this: Everything on a Web page is enclosed in a box. Under normal circumstances, the height of a box is defined by its contents, but the width is defined by the box that encloses it. For example, here’s a sort paragraph of text inside a colored box:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed dolor metus, cursus at, dictum vitae, gravida in, eros.

As you can see, the height of the box is sufficient to enclose the text that it contains. If I add more text, the box grows taller:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed dolor metus, cursus at, dictum vitae, gravida in, eros. Sed egestas libero ac enim. Nulla a ipsum et turpis feugiat mattis. Quisque augue enim, facilisis sed, semper eu, pulvinar et, tellus. Pellentesque tincidunt felis quis massa. Praesent hendrerit posuere neque. Sed rutrum sapien eu quam. Aliquam dictum fermentum nunc. Aliquam erat volutpat.

But the width of the box is different. The width of the box is defined not by what it contains but by what contains it. The box will stretch out horizontally to be as wide as the enclosing box allows. If there is no enclosing box, the box will be as wide as the browser window with which you view it.

This is just fine for text. Heck, this is perfect for text. But it’s not so great when we start talking about things other than text. For example, what if instead of some text, we put a picture in that box:

Pretty girl

That’s not what we had in mind at all. The box shouldn’t stretch all the way across the page like that. It should enclose just the picture. Well, tough, because HTML just doesn’t work like that. Which totally sucks ass if what you’re trying to do is use an enclosing box to simulate a shadow.

So that’s the collapsing-box problem in a nutshell: How do you get a box to collapse to the size of its contents? There are a few different ways to do it. You can set an explicit width for the box, of course. For instance, this box is programmed to be exactly 150 pixels wide:

Pretty girl

But that’s no good in our case because hand-assigning widths to boxes is a giant pain in the neck. Another option involves absolute positioning, but it’s so fraught with perils that I won’t even bother describing it here. No, when I last visited this place, I used the float solution. HTML provides a property called float that causes a box to collapse to fit its contents.

Pretty girl


Unfortunately, as you can see, the float property also causes the box to slide all the way to the left of the enclosing box. Or to the right, if you specify float: right instead.

Pretty girl


Either way, it’s a total show-stopper if what you actually wanted was a centered, collapsed box. And then there’s the need for a clearing element immediately after the collapsing box, and the tendency for boxes that enclose floating elements to disappear entirely when you least expect it … no, if a collapsing box is what you want, you’re pretty much stuck hand-assigning box widths in your HTML, a tedious, repetitive operation. Wait a minute! Tedious, repetitive … I’ve got an idea!


So yeah, a nice little side-effect of my shadow-creating script is that in addition to creating all of the necessary nodes for you so you don’t have to key them into your page by hand, it also assigns the width of the enclosing node for you, effecting a sort of cheat solution to the collapsing-box problem by embracing the tedium and foisting it off on the browser.

Of course, anybody who looks at your page with a browser that lacks support for the Document Model, or one that lacks JavaScript entirely for that matter, won’t see nice mattes and shadows around your pictures. But, as my collaborator put it, “the people with Javascript disabled simply because ‘its bad,’ in todays world of AJAX and web applications, don’t deserve to have computers, yet alone pretty image shadows.” But aside from the quiet glee that comes from knowing people stuck in the 20th century don’t get all the bess and whistles, another significant advantage of this technique is that it can degrade gracefully. That is to say, when the browser in which your page is being viewed is insufficiently equipped to do the job the script calls for, the script can just abort, leaving the page full of otherwise perfectly placed images that just happen to lack shadows around them.

Speaking of browser support, I can absolutely guarantee that this technique works in Safari, Firefox and Internet Explorer. As long as they’re the same as the versions I’m running. And as long as they’re running on my computer. Right now.

Look, I’m just this guy, you know? Exhaustively testing every style sheet and script in every browser that’s ever been made is just not my thing. I use Safari, so I make sure my Web sites and tricks work in Safari. I know lots of people who are stuck on Windows, so I try my best to make sure they work in Firefox as well. And because of those three or four Laplanders who still use Internet Explorer, I at least make an effort to ensure that looking at my site with that browser won’t cause the sun to explode or blood to rain from the sky.

I’m fairly sure that this technique works in the latest Safari and the latest Firefox, and in this old copy of Internet Explorer 6 I’ve got on my Virtual PC disk. If it doesn’t work for you, e-mail me and I’ll make a note of it. Even better, figure out how to fix it and then e-mail me with the answer. Even better still, take my demonstration code, create a new version that works on Edgar’s Web Browser 1.0 for the Commodore 64 © 1987, and then post it to your own Web site. E-mail me the link or something. That’d be pretty cool.

This article wouldn't have happened if Ben Jamieson of Nassau, Bahamas, hadn't nagged me about it. Go visit his site. He's good people. Plus you know you totally want him to invite you to stay at his house sometime.

Posts that might or might not be related to this one

Comments


  1. Css Layout

    This tutorial is for the people who're tired of usi

    Css Layout

    Monday, January 29th, 2007, 1:11 pm


  2. this demo of css dropshadows is fascinating and just the tits for my web site.

    problem is, 1)your documentation -the zip file - left me clueless, 2)i know jack about style sheets, & 3)i am hosted by blogspot/blogger. thus, i have no idea where the stylesheet is kept for me to paste into.

    got any thoughts?

    g randy primm

    Tuesday, April 17th, 2007, 1:13 am


  3. So what was the solution? The article implies the JS will recreate the DOM structure as-per the old markup, but it’s hard to say for sure. There are so many many words, and the topic seems to change to box models half way through without a real conclusion.

    Mike

    Friday, April 27th, 2007, 9:02 am


  4. “There are so many words?” Are you kidding me?

    Leo

    Friday, April 27th, 2007, 9:15 am


  5. Excellent follow-through by this witty writer who actually gives a damn about making sure things are right, and isn’t all caught up in making sure only that HE is right. Way to go; thanks for providing a solution that I will certainly use.

    Coby

    Thursday, May 31st, 2007, 2:23 pm


  6. Very nice - but doesn’t work for img anchors! Damn, could have been perfect for my needs.

    Ray

    Wednesday, August 15th, 2007, 12:30 pm


  7. Any chance these could be used on regular divs instead of just images?

    Logan

    Saturday, September 1st, 2007, 1:44 pm


  8. I like the simple markup, but it seems like this solution is dependent on using a doctype of XHTML Transitional. I tried implementing it into my XHTML Strict site, and it breaks. The only solution I found was to switch it back to Transitional, which I am not willing to do. Anyone have a fix for this?

    Michael

    Thursday, September 6th, 2007, 4:16 pm


  9. Yeah. Don’t use XHTML. Ever. Period. XHTML is a bad thing. It causes browsers to misbehave, as you can clearly see.

    The correct doctype for Web pages is HTML Strict; HTML Transitional is okay in a pinch, but it’s better to use Strict because browsers are more consistent.

    Jeff Harrell

    Thursday, September 6th, 2007, 4:25 pm


  10. I can’t seem to get this to work in IE7….any ideas??? You can see what I mean @ http://dev.lormfg.com

    Blake Sisco

    Monday, December 31st, 2007, 11:05 am


  11. changed url to http://www.lormfg.com

    Blake Sisco

    Monday, December 31st, 2007, 12:33 pm


  12. […] An improved CSS shadow technique- A very robust and easy-to-use technique for applying snazzy looking shadows using only Web technology and a few little image elements prepared beforehand. […]

    101 CSS Techniques Of All Time- Part 1

    Sunday, January 13th, 2008, 2:49 pm


  13. […] An improved CSS shadow technique […]

    440design | 使えるCSSテクニック101選 part1

    Wednesday, January 16th, 2008, 7:14 am


  14. I am not going to send you money for this, but thanks anyways.

    Juan

    Sunday, May 25th, 2008, 12:42 am


  15. I don’t see any shadows, in Opera 9.5, Firefox 3, or Safari 3. What’s up?

    Alan

    Sunday, June 15th, 2008, 10:20 pm


  16. Love the article - made me laugh out loud (which is rare for a CSS tutorial)
    I’m gonna add shadows to everything now! Go me!

    Laura

    Friday, August 1st, 2008, 3:38 pm


Post a comment


Sidebar

Buy my book

The Glacier with Her Name Carved in It
and Other Stories

On sale now

Subscribe

Subscribe to my feed

Search

Tip Jar

This site does not accept advertising.
Please show your support
by sending me all your money.

The fine print

Copyright © 2000-2008
by Jeff Harrell except where noted.

Colophon