Simple CSS drop shadows, revisited
One of the more enduringly popular articles on this site has been “Simple CSS drop shadows,” which explains how to use progressive enhancement techniques to create drop shadows on text and boxes. Although the technique still works, support for complex DOM scripting and CSS as improved dramatically, making these simple CSS drop shadows even easier to do.
Using client-side scripting, this duplicated content is no longer required (unless support for version-five browsers or lower is still required) and a drop shadow can be created on any element accessible via the DOM. Also, this revised method purposely avoids using class names to trigger effects in order for the effect to be as non-intrusive to the basic markup as possible.
(The W3C has proposed two CSS methods to handle text and block shadows, and these are discussed later in this article.)
DOM-styled Drop Shadows
Like the original technique, this method duplicates the headline text and offsets it creating a drop shadow like effect. The box shadow effect places the targeted box slightly offset within a grey div.
In both the examples, there is a unique id attribute associated with the element, but this is not required. The script duplicates the content (and child elements) of the element targetted and requires five values when initiated:
- the DOM node (e.g., the text or box);
- the shadow color;
- an array with the horizontal and vertical offset;
- and the type of shadow wanted (i.e., “text” or “box”).
A headline with a drop shadow
The headline HTML:
<h5 id="pullquote">A headline with a drop shadow</h5>
To create a text shadow in the example above, the script is called this way: dropShadow(document.getElementById("pullquote"),"#AAA",[1,1],"text");.
The script looks for the element with an id of “pullquote” (this could be any DOM node reference, though); sets the shadow color to a shade of grey; and offsets that shadow by 1px both vertically (the first value) and 1px horizontally. Positive numbers place the shadow to the bottom and right of the text; use negative numbers to set the shadow in the opposite direction. The final value ("text") tells the script a text shadow is desired.
The box HTML:
<div id="box" style="float: right; width: 100px; height: 100px; border: none; background-color: #9FC;">A headline with a drop shadow</div>
The box shadow was created by calling: dropShadow(document.getElementById("box"),"#CCC",[2,2],"box");.
Again, the script looks for the DOM node reference; sets the shadow color to a different shade of grey; and offsets that shadow this time by 2px both vertically horizontally. The final value ("box") tells the script to create a shadow on a block element.
The JavaScript:
function dropShadow(shadow,shade,offset,type){ var color = [getStyle(shadow,"background-color"),getStyle(shadow,"color"),shade]; var container = (type=="box") ? document.createElement("div") : document.createElement("span"); var els = [container,shadow]; var content = shadow.childNodes; switch(type){ case "box": container.appendChild(shadow.cloneNode(true)); for(x=0;content.length>x;x++){ shadow.removeChild(shadow.childNodes[x]); } for(x=0;els.length>x;x++){ els[x].style.color = color[1]; els[x].style.position = "relative"; if(x==0){ els[x].style.width = getStyle(shadow,"width"); els[x].style.backgroundColor = color[0]; } else { els[x].style.margin = offset[0]+"px "+offset[1]+"px"; els[x].style.backgroundColor = color[2]; } } break; case "text": for(x=0;content.length>x;x++){ deep = (content[x].childNodes) ? true : false; container.appendChild(content[x].cloneNode(deep)); } for(x=0;els.length>x;x++){ els[x].style.position = (x==0) ? "absolute" : "relative"; els[x].style.color = color[x+1]; } break; } for(x=0;els.length>x;x++){ els[x].style.top = (x==0) ? (offset[0]*-1)+"px" : offset[0]+"px"; els[x].style.left = (x==0) ? (offset[1]*-1)+"px" : offset[1]+"px"; } shadow.appendChild(container); function getStyle(obj,style){ if(obj.currentStyle){ return obj.currentStyle[style]; } else if(window.getComputedStyle) { return document.defaultView.getComputedStyle(obj,null).getPropertyValue(style); } } }
If you are using a JavaScript framework, you can remove the getStyle function and replace those calls with ones to you preferred method.
CSS3 Drop Shadows
Safari 3 became the first mainstream browser to support both of the W3C proposed CSS drop shadow techniques: the text-shadow property and the box-shadow property. The former is nearly standardized (and also supported in Opera 9.5), the latter is still a draft so implementations are still considered proprietary.
A headline with a drop shadow
The headline HTML:
<h5 style="text-shadow: 2px 2px 2px #999">A headline with a drop shadow</h5>
The text-shadow property allows for multiple sets shadows, each with up-to four values: the colour preceded (or followed) by the horizontal offset, the vertical offset, and the blur radius. The blur radius, or the “fuzziness” of the shadow is optional, as is, technically, the colour (although Safari seems to require it). No drop shadows will appear if this method is used and the browser rendering the page doesn’t support these properties.
The box HTML:
<h4 style="float: right; margin: 0 4px 0 0; width: 100px; height: 100px; border: none; background-color: #9FC; -vendor-box-shadow: 2px 2px 2px #999">A headline with a drop shadow</h4>
Again, like text-shadow, the box-shadow property takes multiple shadows, each with up to four values (colour, horizontal and vertical offset, as well as blur radius). Since this is still a draft, those browser who have implemented it are prefix the property with a vendor id. To use it with a WebKit-based browser like safari, replace “-vendor-” in the above example with “-webkit-” — once the standard is set, this would not be needed.