SiteExperts.com Logo Home | Community | Developer's Paradise | Jobs
User Groups | Site Tools | Site Information | Search

Inside Technique : Text Shadows
By Scott Isaacs

A long time ago, we came up with a great idea to create a new formatting command for generating text shadows. We were going to create this by extending the built-in JavaScript object with a new shadow method. The goal was to allow an author to make adding shadowed text as easy as document.write("Shadow Text!".shadow()).

Technically this was an easy problem to solve. By using CSS-Positioning, it is very easy to create HTML that displays the same string twice, with the second one slightly offset from the first, creating a shadow effect. We added the extra challenge of wanting to allow this text to stay in flow, so absolute positioning by itself was not an option.

We came up with an elegant solution. First, a relative positioned DIV is created. Relatively positioned elements live in the flow of the document and also create a coordinate system for any absolutely positioned children. Within this DIV, we created a absolutely positioned SPAN that represented the shadow. The main text was just included in the DIV with no offsets. When finished, the generated HTML is to look similar to the following:

<DIV STYLE="position: relative">
  <SPAN STYLE="position: absolute;font: 14pt arial;  top: 1px; left: 1px; color: gray">
    Shadow Text!
  </SPAN>
  <SPAN STYLE="position: relative; color: black; font: 14pt arial">
    Shadow Text!
  </SPAN>
</DIV>

In the 4.0 browsers, this actually works when embedded directly in the page. However, downlevel browsers see the "Shadow Text" string twice (example is at the bottom of this page).

Now that we had a working prototype, we wrote the shadow method so that the above HTML would be automatically generated. For downlevel browser, we made the code smart enough to return a single instance of the string. In theory, this should of worked great and the code we wrote is included below:

  function shadowText() {
    if (parseInt(navigator.appVersion)>=4) {
      var textcolor = "color: " + ((arguments[0]==null) ? "black" : arguments[0]) + ";"
      var shadowcolor = "color: " + ((arguments[1]==null) ? "gray" : arguments[1]) + ";"
      var fontInfo = (arguments[2]==null) ? "" : "font:" + arguments[2] + ";"
      var offx = "left: " + ((arguments[3]==null) ? 1 : arguments[3]) + ";"
      var offy = "top: " + ((arguments[4]==null) ? 1 : arguments[4]) + ";"

      var str = "<DIV STYLE=\"position: relative;" + fontInfo + "\">"
      str += "<SPAN STYLE=\"position: absolute; " + fontInfo + offx + offy + shadowcolor + "\">" + this.toString() + "</SPAN>"
      str += "<SPAN STYLE=\"position: relative;" + fontInfo + textcolor + "\">" + this.toString() + "</SPAN>"
      str += "</DIV>"
    }
    else // not a 4.0 browser
      str = "<DIV>" + this.toString() + "</DIV>"

    return str
  }

  String.prototype.shadow = shadowText;

The code would add a generic shadow to any text. In addition, optional arguments can be specified for creating custom text and shadow colors, font settings, and offsets. Once we finished, we went back and ran the code. The code worked great and generated the appropriate HTML. In IE4, the effect was rendered correctly but in Netscape Navigator 4.0, the shadow was rendered out of place.

At the end of this article is a demonstration of this code. 4.0 browsers should see a text-shadow and other JavaScript aware browsers should see a single instance of the string "Shadow Text!".

We have spent quite a bit of time trying to find a way to make this code work cross-browser. Instead of continuing to struggle with this, we decided to publish this article and see if anyone else has any fresh ideas on getting this to work in Netscape. If you have any ideas or suggestions, let us know in our Write Once! discussion forum.

Discuss and Rate this Article

Embedded HTML

Shadow Text! Shadow Text!

Shadow Method