http://www.alistapart.com/articles/onionskin/
Editor’s Note: The techniques demonstrated in this tutorial are not for everyone. The design method works its magic by nesting divs that have no semantic or structural value. If that bothers you (and there are good reasons why it might), this is not the tutorial for you. On the other hand, if you wish to create visual effects that expand and contract to fit any object, require no image manipulation, and render the same across all browsers, then “Onion Skinned Drop Shadows” may be just what you’ve been looking for.
Yes, onion skinned. Animators use onion skinning to render what is impossible to seeotherwise: a snapshot of motion across time. Now, web designers can use itto render another seeming impossibility: the truly extensible CSS-based dropshadow.
Tired of reading technique after technique outlining the many ways to skinthis cat? Just consider this a demonstrationof the capacity of CSS to surprise. Just when it looks as though the methodis clear and the wayis defined, one more wandering mind reveals another creative approach. Ifall you glean from this article is a deeper appreciation for the diversity ofsolutions CSS affords, then you’ve benefited far more than any one techniquecould deliver. Read on.
There are several differences between this technique and those offered previously,both here and elsewhere. Some may find it simpler than others, some morestable; but no matter how you look at it, it is more extensible. Withjust one set of simple rules, these new drop shadows:
Onion skinning refers to a technique in time-based arts of overlaying severalframes in a sequence to discern the subtle differences between them. The animatoris simply looking through a stack of layers to see one whole motion througha composite of its parts. What is opaque on one layer can be seen through thetransparent areas on a layer above it. We can do the same thing with div
s.Using CSS, we can stack div
s together in concentric fashion, like the layersof an onion, to form a composite of anything we like. Today, we are making dropshadows.
Three divs, each containing a different shadow image component (illustration), overlay one another to form a composite drop shadow. The markup couldn’t be simpler. Just wrap your object inside three div
s, one inside the other, and give each a class name which corresponds to its role. Since we’re “wrapping” the object, the classes we’ll assign for demonstration purposes are named wrap1
, wrap2
, and wrap3
(.wrap1
assigned to the outer, and .wrap3
the innermost div
).
<div class="wrap1">
<div class="wrap2">
<div class="wrap3">
<img
src="object.gif"
alt="The object casting a shadow"
/>
</div>
</div>
</div>
The CSS is a bit more complicated — but not much. There are basically three things that the style rules must accomplish for the shadow:
div
s surrounding the object to collapse upon it.The basic idea is to assign one of the three shadow image components to each of the div
s through its corresponding class
. The sequence of which div
gets which component is crucial, though. The purpose for having three image components is to use the two small ones at the top-right and bottom-left positions to mask the clipped edges of the large shadow revealing only soft, rounded edges all around.
In order for one image to mask another, it must reside above it in the z-index.We don’t have to worry so much about indexing the stack, since the nested structureof our div
s carry’s an intrinsic stacking order that works for us. We simplyassign the class with the shadow to the outermost div
at the bottom of the stack.Since the div
s inside it will naturally sit on top, we’ll give the classeswith the corner images to them.
.wrap1 {
background-image:url(shadow.gif);
}
.wrap2 {
background-image:url(corner_bl.gif);
}
.wrap3 {
background-image:url(corner_tr.gif);
}
Once we’ve assigned the right images to the right classes, we need to give them position — background-position
, that is. If we left the rules alone at this point, all we would see is a tiled background of “corner_tr.gif” since it’s sitting highest in the stacking order. Remember, onion skinning requires transparency in the upper layers so that we can see what’s beneath. To do this, we’ll cancel the repeating property of all the background images with no-repeat
, and position them where they belong to form the composite of our drop shadow.
Common sense tells us that an image named “corner_tr.gif” should reside in a corner — probably the top-right; ditto for “corner_bl.gif” (bottom-left). But, what about the large shadow image? Does it even need position? Yes — more than any other, in fact. If we want our shadow to fall to the bottom-right of whatever object we put it under, we must specify that direction in our .wrap1
rule. Otherwise, it will automatically fill the div
relative to its top-left corner, the opposite of what we need.
div.wrap1
The outermost div
holds the largest of the three shadow components, which is positioned right bottom
.
.wrap1 {
background:url(shadow.gif) right »
bottom no-repeat;
}
div.wrap2
The second div, nested inside the first, masks the clipped lower-left corner of the shadow underneath, giving it a rounded appearance.
.wrap2 {
background:url(corner_bl.gif) left »
bottom no-repeat;
}
div.wrap3
The third div, nested inside the second, takes care of the clipped corner in the upper right.
.wrap3 {
background:url(corner_tr.gif) right »
top no-repeat;
}
The next step for the CSS is to create the offset that makes the drop shadow drop. This could not be more simple. All it takes is a little bit of padding
on the right and bottom of the innermost div
. When the padding causes this div
to expand away from the object inside it, the two outer div
s expand with it. The result: all three shadow components, positioned along the right and bottom sides of their div
s move in tandem, and can now be seen through the gap created by the padding.
.wrap3 {
padding:0 4px 4px 0;
background:url(corner_tr.gif) right »
top no-repeat;
}
Changing the amount offset for your shadows is almost as easy as simply changing the padding
values on the .wrap3
rule. We say “almost” because adjusting the padding
merely moves the shadow while the corners continue to hug the edges of their containers. To accurately simulate a shift in offset, you’ll need to tweak the background-position
of both corners relative to the padding
.
Some would say that it’s good enough to simply adjust the padding, and leave it at that. No sense complicating things to achieve a nuance that is barely discernable for most people anyway. Others would argue that it cheapens the effect to cut corners this way. If a method will support better aesthetic and technical fidelity, as designers we’re obligated to use it to its full potential. It’s likely that most, however, could go either way.
This image is used below to demonstrate two sets of drop shadow styles. All instances, in both sets, draw their background-image
properties from the same basic set of rules. In other words, the exact same shadow graphics are used for every instance. The only difference is the degree of offset.
In the first set of examples, the offset is modified by adjusting only the padding
valuesin the .wrap3
rule, which moves only the shadow — not the corners.In the second set, both the padding
and background-position
valuesof the corners are modified so that the entire shadow, corners and all, movesas the offset changes.
8 pixels | 12 pixels | 18 pixels |
8 pixels | 12 pixels | 18 pixels |
If you can discern the difference between the two sets, and you prefer settwo, then you’ll need to adjust the background-position
of your corner imagesto compensate for the offset in padding
. Further, you’ll need to add additionalwhite pixels to the outside edges of your corner images. This allows themto move away from the boundary of the div
, without losing their ability to maskthe clipped edge of the shadow underneath. Each shadow style is a littledifferent, and as you begin experimenting with offsets, your particular cornerwhite space requirements will become clear.
A little sleight of hand was necessary to coax every browser that was tested into conformity with this requirement, a potential deal-breaker. But, without this behavior, each and every instance of the shadow style would require the foreknowledge of the object’s width in order to specify the width of the shadow. Obviously, that wasn’t going to cut it.
Most of the browsers tested would allow the div
s to collapse when they receivedthe float
property. This would have sufficed, if it weren’t for thoseof you who use IE5 on the Mac. The mere fact that you exist was reason enoughto explore alternatives. Unfortunately, none were found. At least,none that worked universally.
Some research and experimentation eventually revealed that inline-table
,an obscure CSS display property value, would be the saving grace of thistechnique. Right, wrong, or indifferent, this was all that could be found,and it would have to do. So, using the commentedbackslash method to isolate Mac IE5, we give it display:inline-table
,and all the rest receive float
. So there it is, shrink-to-fit — everything, everywhere, in every browser.
With all three steps in place our CSS looks like this:
.wrap1, .wrap2, .wrap3 {
display:inline-table;
/* \*/display:block;/**/
}
.wrap1 {
float:left;
background:url(shadow.gif) right »»»
bottom no-repeat;
}
.wrap2 {
background:url(corner_bl.gif) left
bottom no-repeat;
}
.wrap3 {
padding:0 4px 4px 0;
background:url(corner_tr.gif) right
top no-repeat;
}
As in the above example, images will often be used with this technique. For those occasions, an additional rule which sets a shadowed image’s display property to block
will help keep unwanted white space from intruding on a good thing. Just add the following rule to your style sheet:
.wrap3 img {
display:block;
}
At this point, you may want to browse the drop shadow gallery to get a feel for what is possible with this technique. We’ve made it easy to download a variety of shadow source images so you can get started.