CSS-Only Box Shading Technique
Wed, Jun 2, 2010 by JF
Introduction
Here is a fun technique to add shading to your web pages using only CSS with PNG images, without using JavaScript, Flash, server-side scripting, or Photoshop, and remain totally independent from colors and textures.
Try it here.
Background
Most shading techniques suffer the drawback of the core technology they use:
- Photoshop: images must be individually styled for each pattern combination
- Javascript: CPU intensive
The main issue with Photoshop techniques comes from the time spent creating images, and from the complexity of the code to keep tack of them. For each color/teture combination, 8 images (4 corners and 4 edges) are required.

One technique called “sliding door” reduces these elements to 6, but requires larger images:

A new approach
Our technique is based on the same basic idea used in 3D rendering engines which separate textures from shading. Here is an example showing the difference between shades + textures, and shades only:

The first step is to create the shade PND images. Simply use a mask to hide the box content (see the included files):

To optimize this technique, we can reduce the top and bottom elements’ width, and the left and right elements’ height to one pixel.

To use on a web page, we simply create a box element normally, wrap it in a “shade” container and add the required elements.
For the most complex case:
<div class='shade'>
<div class='box'>
<!-- content -->
</div>
<div class='TL' />
<div class='T' />
<div class='TR' />
<div class='L' />
<div class='C' />
<div class='R' />
<div class='BL' />
<div class='B' />
<div class='BR' />
</div>
For fixed-with boxes, such as page containers, we only require 3 elements (top, center, and bottom):
<div class='shade'>
<div class='box'>
<!-- content -->
</div>
<div class='T' />
<div class='C' />
<div class='B' />
</div>
Likewise, fixed-height boxed such as title containers only require 3 elements (left, center, and right):
<div class='shade'>
<div class='box'>
<!-- content -->
</div>
<div class='L' />
<div class='C' />
<div class='R' />
</div>
You do not have to create the shade element, you can just apply the shade class to an existing one. The only purpose of the shade element is to serve as a wrapper and an anchor for absolute positioning.
Fore each shading element, we define a negative margin (here 10 px) to accommodate the shade and use a negative z-positioning to place the shade below the content of the box.
.shade {
position:relative;
}
.shade .TL, .shade .T, .shade .TR,
.shade .L, .shade .C, .shade .R,
.shade .BL, .shade .B, .shade .TB {
position:absolute;
z-index: -1;
top:-10px;
left:-10px;
right:-10px;
bottom:-10px;
}
.shade .TL {
background: url(s/tl.png) no-repeat left top;
}
...
As always, the best way to fully understand a technique is to look at a demo, or to download the source. Next time, we will look at a Drupal theme which implements this technique.
Cheers!
JF
ipwa posted on June 3, 2010 3:32 pm
I think since this is a fixed width box (from your demo), a better idea is to use one image for the top, one for the bottom and another for the content which is repeated on the y-axis. I would make the center image 10px tall instead of 1px (not much difference in file size) since some older computers have performance issues repeating images of just 1px.
Or like Bevan says use the CSS property, webkit and mozilla support it.
gmclelland posted on June 3, 2010 2:13 pm
Great technique,
What browsers does this support?
jf posted on June 3, 2010 5:12 am
Yes, a few others have done shadows using PNG, I have never seen something totally independent from the textures themselves.
Plus, and I have not covered it in the text, there is more to this technique than just the shadows, as it is possible to add texture and edges to the boxes (there is a fine translucent white edge on the top and sides of the boxes to give them more "life").
And as for the CSS box-shadow, it is coming, but it is not yet supported by IE which still has the lion's share of the market.
And on Gecko and WebKit, it has been available until recently only via the proprietary -moz-box-shadow and -webkit-box-shadow.
I am just too impatient to wait!
Finally, with this technique, if you want to "upgrade" certain browsers to CSS shadows, it is quite easy to hide the extra DOM elements and add the box-shadow directives, all in CSS, because the DOM elements are not nested. This is why I can alter the transparency of the shadows with jQuery without affecting the content!
Cheers!
JF
Bevan posted on June 3, 2010 3:08 am
Nice! But I this is not new. Panels (I think) and others have been doing this for a while.
Even simpler, more powerful and IMO interesting is CSS3's approach to this with the box-shadow property; http://www.css3.info/preview/box-shadow/
Chrome supports it — but probably not many non-webkit browsers yet.
Post new comment