text-shadow hack for firefox

I was reading through the list of improvements for KDE 3.4rc1, which I compiled over the last two days on my lappy. One thing stood out for me, as I’m a web developer – the CSS3 item “text-shadow“.

Konqueror screenshot

After writing up a test page and viewing it in Konqueror, I realised that it could be faked pretty easily by using JavaScript and CSS2’s opacity.

So, I set to work. The script I’ve come up with reads through your CSS, notes what elements have a text-shadow applied to them, then fakes the text-shadow.

Firefox screenshot

Here’s an example page for you to see it yourself.

“So what?”, I here you say.

  • Firefox does not yet support text-shadows.
  • You don’t have to write hacky CSS for this – just include the script.

This may turn out useful for work, so I’ll see what I can do about IE, tomorrow.

update: I grabbed a copy of Dean Edwards’ cssQuery script. Now, the example should work just about all the time (in Mozilla-based and KHTML-based browsers).

20 Replies to “text-shadow hack for firefox”

  1. Unfortunately in IE the shadowed text appears on the far left of a page when I tried to apply it to text inside left or right floated span tags that are in a centered div tag. Works perfectly in Firefox though, so for now I will use the .js with the IE specific “else if(window.attachEvent)…” commented out and use the IE specific CSS hack for shadow filter. Email me if you want an example url.

  2. Ok, I take back the “works perfectly in Firefox” bit. Resizing the width of the Firefox browser reveals the shadowed text maintains it’s “absolute” position literally, while the actual text adjusts to stay in the centre of the browser. Refreshing the page re-aligns it, so for now I can live with that minor bug. Hope this helps with any planned improvement to the code.

    P.S. The IE specific FILTER css attribute only being applicable to a restricted list of tags without using inline style=”” for every tag is enough to convince me it’s not a good workaround. Let me know if my email replies didn’t get to you.

  3. Mardeg, yes, you are right about the resize. I do have a solution for that (partly implemented in a later project), but have not had the time to integrate it into this one yet.

    I have not played with the IE filter yet, but I am certain that every problem has a workaround. As soon as I have finished my Border project, I’ll get back to this one and add in fixes for the points you have noted.

  4. I’m afraid I haven’t looked at it in quite a while. However, as you’ve just reminded me of this script’s existence, I may put some work into it over the next few days.

  5. I’m not sure if you’ve noticed this, but it doesn’t work in Opera either.
    I’ve found out that the reason for this is Opera strictly adhere’s to the W3C spec of .addEventListener only being applicable to nodes, and since it doesn’t consider window. a real node, then window.addEventListener() doesn’t exist in Opera. Oh well, at least it correctly ignores it.

  6. On firefox 1.0.7 (i only tried this) color as “#…..” does not work. Reason: it’s returned as “rgb(x, y, z)”. and this is slipttet into “rgb(x,”, “y,”, “z,”.Solution: r=r.replace(/[ ]*;.*/,”); r=r.replace(/, +/g,’,’); var parts=r.split(‘ ‘);  This line replaces “, ” with ” “. What i the license of your javascript code? I saw that cssQuery is CCL. Does this also apply to your code?

  7. Correction about Opera. I was wrong with the reason it fails. The correct reason is document.styleSheets.length is undefined in Opera. 

  8. Thanks guys. I haven’t looked back on this code in a while. Maybe I will get around to it at some point.Michael, consider it “freeware”. Do with it as you will. I must have forgotten to add my usual license, which goes something like this: Copyright Kae Verens (kae@verens.com). Do with this as you wish, but keep this license in the code. 

  9. Firefox v1.5 release is due to come out within the next week or two, perhaps you can get the beta available from mozilla’s site to see how the script performs in it. I just had to remove the text-shadow.js completely from my page because it doesn’t line up with the text in 1.5 for all OS platforms (a screenshot someone gave me has it below by half a line and to the right by about 3 chars of the original text).

  10. This is best initiated as soon as the text appears on the page instead of after all the binary content is loaded, so at the beginning of the file replace:

    if(window.addEventListener)window.addEventListener(‘load’,textShadows,false);
    else if(window.attachEvent)window.attachEvent(‘onload’,textShadows);

    with:

    if (document.addEventListener)document.addEventListener(“DOMContentLoaded”, textShadows, null);
    /*@cc_on @*/
    /*@if (@_win32)
    document.write(“”);
    var script = document.getElementById(“__ie_onload”);
    script.onreadystatechange = function() {
    if (this.readyState == “complete”) {
    textShadows(); // call the onload handler
    }
    };
    /*@end @*/

    and to stop textShadows() from being called by more than one onload event, insert the following lines at the very beginning of the textShadows() function:

    if (arguments.callee.done) return;
    arguments.callee.done = true;

    Btw, this still doesn’t work in Opera 9, and still messes up when the browser is resized.

    I’m wondering if anyone has tried this as a greasemonkey script (the Firefox extension that lets you insert javascript into any page)?

  11. Oops, the document.write line for the IE hack disappeared from the above post. Use this line and replace the [ ] with normal angle brackets for tags:

    document.write(“[script id=__ie_onload defer src=javascript:void(0)][/script]”);

  12. This technique seems to have another issue that I didn’t see mentioned: it duplicates the text multiple times, which is bad for text selection; un?semantic; and, I would imagine, poor for assistive technologies such as screen readers.

    Quote (Mardeg): I’ve found out that the reason for this is Opera strictly adhere’s to the W3C spec of .addEventListener only being applicable to nodes, and since it doesn’t consider window. a real node, then window.addEventListener() doesn’t exist in Opera.

    The correct code is document.defaultView.addEventListener anyway.

    Quote (Mardeg): (document.addEventListener)document.addEventListener(”DOMContentLoaded”, textShadows, null);

    I don’t believe that DOMContentLoaded is supported by Safari. The easiest way to get this effect is to call the script as it’s loaded by calling it at the end of the body element instead of within the head element. In this case, the call to the (on)load and/or DOMContentLoaded events becomes unnecessary.

  13. FYI, the add-on includes a solution of the problem:
    > This technique seems to have another issue that I didn’t see mentioned: it duplicates the text multiple times, which is bad for text selection; un?semantic; and, I would imagine, poor for assistive technologies such as screen readers.

  14. It’s a fair cop. As mentioned in the title, this script is just a hack, and should not be considered as absolutely correct. It was done to demonstrate that it is possible to do text-shadow in Firefox even if Firefox does not yet do it natively.

    To be fair, though, screen readers should probably not be running JavaScript anyway, so this script should be safe in that case.

    (I’m also on the mailinglist for the Firefox bug entry for this, btw)

    If you liked this hack, please also see my border-radius hack.

  15. Ah, I forgot to add last time, but CSS3 will be included in Opera 9.5. And since opera users are more tech-aware then IE users, they’ll update to the new version quicker.

    So that will be 3 of the 4 main rendering engines all supporting text-shadow (which will be something like 8 of the top 9 browsers!)

Comments are closed.