Creating Cross Browser Compatible CSS Text Shadows
Way back at the beginning of september, I was having a discussion with one of my friends about drop shadows in CSS. Currently, the only web browser which supports the CSS2 text-shadow property is Safari, which does the job really rather nicely. At the time, I made the statement that you could get pretty much every other browser to create nice text shadows as well, without having to add lots of extra markup to your HTML.
So, the challenge was simple. Come up with some CSS which will produce drop shadows in as large a percentage of peoples’ web browsers as possible, leaving the browsers which are incapable of showing text shadows with unstyled text. Sounds simple? Well, for the most part, it was…
There are already tutorials out on the web which tell you how to produce text-shadows for various web browsers. The problem is, they all seem to focus on one particular browser, rather than producing a cross browser compatible solution. Of course, the “one true solution” is to wait until everything supports the CSS2 text-shadow property, but that day won’t come for a good while yet. So, in the mean time, here’s how I put everything together into one package so that it all “just works”.
Start with a Safari
In a big break from tradition, I decided to start by writing the CSS Apple’s Safari web browser. But why would I do this? Although I generally start work on the Mozilla group of browsers, due to the fact that they have the highest usage of the browsers which have good CSS implementation, in this instance Safari implements the text-shadow CSS property staight out of the box. Sadly, at this time, Mozilla does not — hence the need for this article.
Anyway, the CSS needed for Safari is as follows:
In an ideal world, that’s where this article would stop. Unfortunately, as I said at the top, there’s a bit more of a challenge to go yet. But first, lets do the next easiest bit.
Dropping some shadows with Internet Explorer
Although Internet Explorer doesn’t use the text-shadow CSS property, it does provide a nice easy way of creating text shadows: the shadow filter. This is well documented on other sites, so I’ll just give you an example here. To create similar shadows to the example above for Safari, you’d use the following CSS:
Mixing IE/Win and Safari
Adding the two techniques together which we’ve used so far is nice and easy. Neither one gets in the others way, since neither one understands what the other means. Consequently, we can just concatenate the two rules to get a shadow in both IE/Win and Safari.
Shadows in Mozilla
Here’s where things start getting meaty. Since the Gecko based browsers do not know about the previous two methods of creating shadows, we need to create our shadows in some third way.
There are various ways that we could create the text shadows in the Gecko browsers. You could, for example, make use of your favourite image replacement technique to replace the text to be shadowed with an image of some shadowed text. That’s a fine technique, but not the one that I chose. What I chose to do was create a piece of “shadow text” using the :before pseudo-element.
.shadow < line-height: 2em; white-space: nowrap; >.shadow:before < display: block; margin: 0 0 -2.12em 0.15em; padding: 0; color: #666666; >#shadow_header:before
The code above first sets up the element which is to be shadowed, giving it a line height of 2em — enough space to position the shadow element behind it. The element is also set not to wrap, as wrapping would destroy the effectiveness of the :behind pseudo-element.
As mentioned earlier, the :before pseudo-element is where the meat of the technique is for the Gecko browsers. The code itself should be pretty self-explanatory — all it really does is move whatever is written as the :before content to the right and down a bit, and colours it a light gray.
In order to use the .shadow class multiple times on the same page, and still use the :before technique, it is necessary to create an extra id for the element which is to be shadowed. This is the only change which is made to the html of your page. This addition allows us, as shown above, to create an extra rule which states the text of the shadow itself.
Hmmm, that’s not very nice
“Just wait one cotton picking minute!”, I can almost hear you cry. “But that gave me a shadow in Safari too!” Well yes, it would do — Safari knows how to use the :before pseudo-element. The problem with this is that it means that you can’t just do a nice easy concatenation to join the three previous rules together. You can see below what happens when you simply try to join them together.
Admittedly, depending on your eyesight, that doesn’t look too bad in Safari. However, if you know that both the :before shadow and the text-shadow shadows are being applied, then you can see them, and the effect does jar. At least, it does for me. Which is why I started looking for a CSS hack which would allow me to hide the :before rules from Safari only.
Hiding CSS from Safari
Finding a CSS hack which would allow the hiding of CSS from Safari was not an easy one. I searched on and off for about a week, and could find nothing that worked. Then, as if by magic, Mitchell Stokely posted about the Stokely Safari Hack which he had written on the CSS-D discussion list that I watch. It worked like a charm.
Basically, the Stokely Safari Hack works using a complicated system which first “narrows the agents focus, then relies on a difference in how IE 6, Safari, and Netscape parse properties using brackets”. Frankly, it’s all a little complicated, but it works! Using the following hack, Internet Explorer sees its filter: Shadow method, Safari only sees the text-shadow CSS property, whilst Gecko based browsers (and any other browsers which know about :before ) will fall back to the :before text shadow.
Here’s how we do that (no, I’m not going to try and explain how it works):
/* default setup that everything sees */ .shadow < /* needed for Internet explorer */ height: 1em; filter: Shadow(Color=#666666, Direction=135, Strength=5); /* Needed for Gecko */ line-height: 2em; white-space: nowrap; >/* * used by browsers which know about * :before to create the shadow */ .shadow:before < display: block; margin: 0 0 -2.12em 0.15em; padding: 0; color: #666666; >#shadow_1:before < content: 'In shadow'; >#second_2:before < content: 'Happy Shadowing!'; >/*\*/ html*.shadow < [color:red;/* required by Safari * so that [] is correctly * begun. associated with * the property, yet hiding * it. Seen by IE6 */ /* * seen by IE6 and Safari, but hidden * from Gecko */ text-shadow: #666666 5px 5px 5px; ]color:auto; /* resets color for IE6 */ >/**/ /* * end hack using dummy attribute selector * for IE5 mac */ .dummyend[id] /*\*/ html*.shadow:before < [color:red;/* required by Safari. seen by IE6 */ /* * seen by IE6 and Safari, but hidden * from Gecko */ display: none; ]color:auto; /* resets color for IE6 */ >/**/ /* * end hack using dummy attribute selector * for IE5 mac */ .dummyend[id]
In the example above, the html which I used to get the text shadowed across all browsers was
In shadow
. Whenever you’re adding shadowed text to your pages using this technique, ensure that you add a relevant id, and duplicate the text of the shadow into your style sheet.
And that’s all there is to it. Just in case you don’t have a lot of browsers available to check things in, here’s how it looks to me in a few of mine:
Browser Compatability
This cross browser drop shadows technique has been tested in the following browsers. If you test the technique in any other browsers, please leave a comment here so that it can be added to the list.
- Safari 1.2.4, 1.3.1 — Displays text-shadow shadow.
- IE5.5/Win — Displays filter: Shadow shadow.
- IE6/Win — Displays filter: Shadow shadow.
- IE5/Mac — No shadow. Degrades happily.
- Mozilla 1.7.3 — Displays :before shadow.
- Firefox 1.0, 1.0.6, 1.0.7, 1.5 Beta 2 — Displays :before shadow.
- Opera 7.54, 8.5 — Displays :before shadow.
Caveat
This hack is just that — a hack — and is only really useful for use right now. As soon as any browser other than Safari is taught how to use text-shadow , the hack will have to evolve to allow that browser to see the text-shadow rule as well.
I hope that someone out there finds this useful. If you find any problems with the technique, or any browsers which do not behave as expected, please tell me!
References
WebThang Text Shadows. An overview which shows how to use the filter: Shadow Internet Explorer technique.
Text Shadows with CSS. This page uses the :before technique to create shadows.
The Stokely Hack. Without this hack, there would be no article here today. It’s complicated, but to my knowledge it’s the only current way possible to give CSS to soley the Safari web browser.
If you enjoyed reading this and would like other people to read it as well, please add it to del.icio.us, digg or furl.
If you really enjoyed what you just read, why not buy yourself something from Amazon? You get something nice for yourself, and I get a little bit of commission to pay for servers and the like. Everyone’s a winner!
text-shadow
The text-shadow CSS property adds shadows to text. It accepts a comma-separated list of shadows to be applied to the text and any of its decorations . Each shadow is described by some combination of X and Y offsets from the element, blur radius, and color.
Try it
Syntax
/* offset-x | offset-y | blur-radius | color */ text-shadow: 1px 1px 2px black; /* color | offset-x | offset-y | blur-radius */ text-shadow: #fc0 1px 0 10px; /* offset-x | offset-y | color */ text-shadow: 5px 5px #558abb; /* color | offset-x | offset-y */ text-shadow: white 2px 5px; /* offset-x | offset-y /* Use defaults for color and blur-radius */ text-shadow: 5px 10px; /* Global values */ text-shadow: inherit; text-shadow: initial; text-shadow: revert; text-shadow: revert-layer; text-shadow: unset;
This property is specified as a comma-separated list of shadows.
Each shadow is specified as two or three values, followed optionally by a value. The first two values are the and values. The third, optional, value is the . The value is the shadow’s color.
When more than one shadow is given, shadows are applied front-to-back, with the first-specified shadow on top.
Values
Optional. The color of the shadow. It can be specified either before or after the offset values. If unspecified, the color’s value is left up to the user agent, so when consistency across browsers is desired you should define it explicitly.
Formal definition
Initial value | none |
---|---|
Applies to | all elements. It also applies to ::first-letter and ::first-line . |
Inherited | yes |
Computed value | a color plus three absolute lengths |
Animation type | a shadow list |