JavaScript Image Replacement

As discussed previously on A List Apart,
Fahrner Image Replacement (FIR), a technique developed to allow designers to use image-based typesetting while meeting accessibility requirements, only serves its intended purpose when screen readers misbehave.

Article Continues Below

The premise of FIR is simple: set the text-containing image as the background of an XHTML element and hide the corresponding plain text by nesting it in a span and setting the span’s visibility to hidden, or display to none.

Most screen readers, however, are clever enough to realize that text set to visibility: hidden or display:none should not be read.

That’s why Peter-Paul Koch came up with the idea to use JavaScript to replace plain text with image-based text (on the css-discuss mailing list), and that’s where the technique explained here comes in.

Why JavaScript?#section2

There are already many solutions to the problem, each of them using CSS to
hide, move, or stack the images and the text. The forum entries
related to Joe Clark’s FIR article propose several.

By using JavaScript, we have an opportunity none of these solutions give us:
the markup can be plain vanilla XHTML, with no need for any special IDs or
CSS tricks in it.

Non-JavaScript users will simply see the headlines as they are, and designers still have the chance to style the plain-text versions with CSS.

The only users whose experience is negatively affected are those
with JavaScript turned on and images turned off. These users will see the
text replacement for the image. An exception are Mozilla users — but more on that later.

Enough talk, show us the goods#section3

Take a look at the demo page and you’ll see the technique in action. This is achieved by using one script together with an array of image names.

replaceImages = new Array(
  ’About us|about.gif’,
  ’Contact Us|contact.gif’
  );function firdom(){
  if(document.getElementsByTagName && document.createElement){
    for (l=1;l<=6;l++){
function scanandreplace(h1s,tag){
        // or newimg.src=chunks[1];

The array replaceImages needs to be defined either once in an
external JavaScript or for each page individually. It tells the script
which headline to replace with which image.

The text that will be replaced and the URL of the replacement image
are separated with a “|”.

In the below example, any headline with the content “About Us” will be replaced with the
image “about.gif”, any headline with the content “History” with
”history.gif” and so on.

replaceImages = new Array(
’About us|about.gif’,
’Contact Us|contact.gif’

All you need to know to use the technique is how to assemble this array. Then you can add the array to your page, include the script via its own script tag, and enjoy the graphical headlines.

If you are not familiar with the DOM and you don’t want to know about it, skip the next bit and proceed to “Where it fails.”

Under the hood — how it works#section4

So you want it more technical, then? Okay, firdom() does the following:

First we check if our browser can deliver what we need by testing for DOM
capabilities. This prevents old browsers from trying to do what they can’t.

if(document.getElementsByTagName && document.createElement){

Then we loop through all possible headline levels (<H1> to <H6>) and call another function, asking that one to find and replace all headlines with the current level.

for (l=1;l<=6;l++){

This function, scanandreplace(), takes each one of these headlines and compares its content (the nodeValue of its first child) with the text preceding the “|” in each element of the array replaceImages.

function scanandreplace(h1s,tag){

If there is a match, we create a new image element and set its source to
the text following the “|” in the current element of replaceImages.

To take an additional accessibility precaution, we set the alt attribute of the new image to the text of the headline.


All that remains to be done is to replace the original text content of the
headline (its first child), with the newly created image — and voila, we have
graphical headlines.


Where it fails: Mozilla’s method of imageless surfing#section5

This technique works in every DOM-compliant browser. Without JavaScript, you
will see plain-text headlines (search engines will also see and index the plain-text versions). With images turned off, you will see the alt text within headline elements.

That is, unless you use Mozilla. If you go to Mozilla’s web features, you see an option that allows you to stop “loading images.” If you uncheck that checkbox, Mozilla stops loading images. Oddly enough, it does not
show the alt text either. This happens to every image, and also to
our little routine here. At the time of publication, we don’t know of any workaround.

Gimme gimme gimme#section6

You can download the script here. Watch its homepage for fixes and changes. Enjoy.

57 Reader Comments

  1. Maybe I haven’t been following FIR enough, but I don’t understand what this method solves that the ALT attribute on images doesn’t.

    What are the weaknesses of specifying ALT text that make needing to insert the text explicitly necessary?

  2. Pete, the reason FIR could be considered preferable to alt text specification has to do with display in PDAs, mobile phones, etc. Imagine you have a header image 600 pixels wide but a web enabled cell phone only has 300 pixels of horizontal real estate. You will be using twice you allotted horizontal space and get a horizontal scrollbar. With the FIR technique the cell phone/PDA user will see your header text instead of the genormous image with no horizontal scroller.

  3. It is the year 2003, and we are still trying to figure out the best way to swap an image on a web page?

    I’m a big fan of web standards, mind, but it seems like maybe we missed something….

  4. I think this is a good script, but Matt Ripley hit it on the head. The beauty of using XHTML and CSS is it’s simplicity and wide audience.

    In my opinion, adding an extra [span][/span] to layer my image over text is the best way. Overall, wether images off or CSS off, the page is still readable and, for the most part, usable in all browser types.

  5. Instead of creating a replaceImages array (which need to be updated all the time), wouldn’t it be better to replace images based on their name? For example if the image is foo.png, then you’d replace it with foo2.png. You’d need to use the string methods, but that would allow you to skip on the javasctipt script maintenance.

  6. In my opinion JavaScript should add behaviour to the browser, instead of doing what CSS is capable of. But, the idea described in this article sounds a lot better than the cluttered CSS normally used to achieve this effect.

    However, I don’t like the JavaScript code used in this article. I realize that this is because of how I’m used to code. I certainly won’t use this code on my own website, though chances are that I’ll write my own version/interpretation of it one day.

    Jean-François Bastien: I think you’ve missed the point. This isn’t about swapping different images, it’s about replacing a textnode by an image.

  7. I work with JavaScript on a regular basis in lots of situations and it has some great uses, but I don’t think that this is a good one. A couple things:

    1. The script is poorly constructed. There are no local variables used, just globals, so this script has the potential to kill other scripts running at the same time.

    2. It’s not pretty: It runs onload, so you are going to have to wait for the entire page to load (including images and media) and then your titles will change. This is going to look bad, especially on pages that are more than just text. Adding to the problem, if your title images aren’t tiny, you’re going to have to wait for them to load as well. Some of the problem could be solved by putting the function call at the end of the body, but I don’t think that’s an elegant solution either.

    3. It isn’t properly debugged. If you have any whitespace before or after the title, the script won’t work in Mozilla.

    I don’t mean to tear things apart, but it’s a bit disappointing to see these problems with something published here.

  8. Why o why is this published? Simulating CSS effects (element{content:url()}) with JS is truly evil if the intended effect is not dynamic. This can even be done with valid XHTML 1.0 Strict (or 1.1), without even touching the CSS.

  9. Mark Wubben: What I meant was that the javaScript could use info from the thing it want to replace itself to “guess” the proper image name, for example if I want to replace an image I could replace foo.png by foo2.pnng, if I want to repllace a header I could replace a header containing “A Title” by the image a_title.png. Maybe it the info could be in the id attribute of the header (or image), or maybe a particular class attribute could tell the jaVascript to replace the image or not.

    The whole idea I’m advocating is code portability, smart programming, and small maintenance time.

  10. This is an interesting technique. One thing I immediately considered when I read it was moving the image filenames out of replaceArray[] in the .JS file, and into the page markup, thereby reducing weight on an image-heavy site. Perhaps consider storing the SRCs inline as an invisible tag/attribute? I was considering something like this:

    About Us

    Then, getElementsByTagName(‘H’+n) for each tag you want to replace, loop through the list as you do now, and check firstChild.tagName && firstChild.getAttribute(‘title’) to detect appropriate elements and the filenames with which you could replace them. Rest of script proceeds as normal.

    I haven’t actually touched a browser with this but it should work :). The SPAN should be invisible to the user, and it should mean that you can have one unaltered JS file for each page on which you want to use the technique.

  11. …I see ppk has already suggested using inline attributes in the linked writeup on his site. Everyone, read that if you haven’t already, it contains quite a bit of feedback and an alternate script with browser compatibility results.

  12. This was referenced in the comments of the “Facts and Opinion About Fahrner Image Replacement” article at Doesn’t this hide text without additional markup in the html? Is there something I’ve missed here? It’s simple and works on my PDA phone which ignores CSS and shows the text.


  13. >For gods sake PPK stop crying. It’s an image replacement script….not world peace. Jeez

    1) For better or worse, this is my idea. If you want to extend it or criticize certain aspects, fine. If you just want to butcher it because you don’t know what you’re doing, I’ll tell you to get lost. Harshly, if necessary.

    2) The matter goes beyond a simple image replacement. I suggest you reread my ‘Theory’ paragraph.

    3) Web developers expect ALA to deliver serious, good content, which means they won’t hesitate to use this trash script in their own pages. They trust ALA, but their trust is misplaced in this particular instance.
    ALA doesn’t know what it’s doing when it comes to JavaScript, either.
    Fine with me, but then please stick to the brilliant CSS and accessibility stuff and don’t publish JavaScript articles any more.

  14. Unfortunately I have to agree with both David S’s and PPK’s comments…this script is poorly written and, like many scripts I see out there, does not take into account a number of things:

    1. The globals, as David S mentioned.
    2. The assumption that this would be the only script to be run onload.
    3. The obvious errors (PPK’s mention)

    PPK’s response article, while a bit harsh, seems to be dead on, with one exception: XHTML not allowing custom attributes. The fact of that particular matter is that is does, you just have to use your own namespace to qualify it, like so:

    The script

    I’d hate to say it, but I’m with PPK on this one: if the editors of ALA aren’t willing or able to recognize poorly written JS, then they should refrain from posting articles based on it. Considering that ALA is such a trusted resource…too many who do not know JS too well will take it for granted that it is of the same quality as the rest of the articles.

    Personally, I see absolutely nothing wrong with using CSS to effect image replacement; it really is the right place for it, as an image replacing text is a presentational function, not a semantic one (and in this respect, I would argue that FIR and Pixy’s methods *are* a better choice than PPK’s, only because it does not touch the semantic data that represents the document).

  15. Well first I’d like to say I’m a big fan of ALA and PPK.

    I agre with PPK about this article, I think ALA should get any JavaScript aticles checked by people that know how to JavaScript.

    And then mobile phones and the like…
    Has anyone tried using these site with them?
    Why don’t mobile phones display the alt=”” text instead?
    Or do they?
    or maybe they show images? – (if so it wouldn’t take much for a mobile phone browser to show images that fit and the alt=”” text for images that don’t.)

    Thirdly, custom attributes are brilliant, by far the most elegant solution (other than css), I’ve used them loads, but am wondering about browsers’ support, does Mozilla recognise custom attributes in any HTML (HTML 4.1 for example)?

  16. “Discuss — Was it good for you, too?”

    No, it wasn’t good for me ‘too’. Maybe for some kids with poor internet connection…

    “JavaScript Image Replacement”

    I agree with Anne and some others that idea is silly — css will not replace text with image but will show to you any text you like:)) so all that game… “do not write ‘heading’ but ‘HeadiNG'” etc… is not very useful imho… but it is not important at all…

    What is really important is:

    *** “by Christian Heilmann” ***

    1. That Cristijan Hellman misspelled authors name and wasn’t sorry in public about that (and another mistake that ala did correct that error on incorrect way… they needed to underline that correction [were like this, now is like this: we are very sorry etc.] for example…).

    2. That Cristiaam Hejlman just mentioned ppk using known, ignoring style as ‘by the way’ and that is very rude (re: “That’s why Peter-Paul Koch came up with the idea […skipped…]”.

    3. That Kristian Xelman didn’t give to article the appropriate tone as: “Peter-Paul Koch wrote small (java)script as alternative solution for known CSS trick *** and it was my inspiration for the next code ***” etc. etc. and before publishing he could write to ppk (as obligatory btw.)

    etc.4th..: That neither Krisstijan or ALA didn’t answer on ppk claim in this ‘Discuss thread’ so now we do know what they think about their readers. I saw many ‘discuss this article’ (sub)forums where authors *are* involved in discussion because they really do care about people who read their articles.

    About programming level… I am not fun of ppk:) (or anybody else probably) or javascript but… what I perfectly well know (and remember) that he is very tough in javascript methods and language and that, few years ago I’ve spent a lot of time visiting his site and learning javascript there. I do not remember any hCrisctian in connection with javascript.


    ALA should write to ppk and use his page (or another ppk’s text) as public answer on the article. He has right on that because his name was mentioned in the text. It is basic.

  17. I think the real problem here is that the article wasn’t written by one of the “in” crowd. If Scott Andrew or Eric Meyers or Anil Dash or any of the other’clan’members that spend most of their waking moments stroking each other writes it….it’s a big hit.
    Period! Same old same old.

  18. I use FIR (with visibility:hidden, not display:none), and tell the User Agent that this particular portion of the StyleSheet is only for the eyes of screens, projections, and prints (either with media=”” in the link element or with @media in the StyleSheet).



  19. > I think the real problem here is that the article wasn’t written by one of the “in” crowd.

    Personally, I don’t think it matters who wrote it. Bad code is bad code. Period. How can you expect it to be well-received if it is poorly written, error-prone, and not thoroughly tested? Surely you’d expect something better.

    All it takes is someone who deals with this stuff on a day-to-day basis to see the holes and those types (myself included) would rather not have the internet filled with crappy scripts. I’d only hope that ALA wants the same.

  20. Am I missing something?

    Why not just use the “text-indent:-100px” method which does all this, AND doesn’t require client side scripting? If you use px’s as your width, then it seems to work best.

    I really do think it’s a sad day when I see articles advocating replacing browser functionality with client-side scripting (like that method of calling PNGs which involved JavaScript) – and I certainly don’t see why non-JavaScript users should be given a worse user experience when they don’t have to.

  21. I am shocked to get such harsh words from PPK and others without ever hearing from them beforehand.

    PPK came up with the idea on a mailinglist. 20 minutes later I answered to the mail with this idea, CCing him, asking if that is an idea to start with.

    Some time passed, as ALA, same as takes some time to publish.

    No word there, no word of PPK on the list that he published a version on

    I appreciate the coding issues, but I also would like to be told when someone has a problem with me personally before getting slacked off here. If I played in your domain, sorry, if this article sucks and every javascript that does not adhere to OO principles sucks, delete 90% of the script outlets on the market.

    So the facts are:

    – I published a first version of this script on the mailinglist, CCing PPK.
    – I didn’t hear any complaints beforehand
    – noone stopped him from submitting an article here either, promoting the brilliant (and that is not sarcasm) even further, rather than assuming people would just find it there.
    – PPK had the same idea, not the same script (else it would be a lot better)
    – There are many ways to achieve an effect (I Loved Anne claiming XHTML1.1 and CSS2 can do the same – but where are the users whose browsers support it?).

  22. >PPK came up with the idea on a mailinglist.
    >20 minutes later I answered to the mail with
    >this idea, CCing him, asking if that is an
    >idea to start with.

    Interesting. I cannot remember, but I looked it up in the css-d archives and it turns out you’re right.

    Frankly, I get a lot of such mails, and if I’d have to answer them all I wouldn’t have time for anything else. Besides, at that moment I was very busy with writing my JIR script and getting quirksmode ready for publication.

    So what I think happened (again, I cannot remember) is that I saw your data array, decided that it was not the way to go, and ignored your mail.

    >Some time passed, as ALA, same as
    >takes some time to publish.
    >No word there, no word of PPK on the list
    >that he published a version on

    Now this is untrue. On the same day you wrote your mail to me, I announced on css-d and I explicitly said that it contained a JIR script.

    So you could have known.

    >I appreciate the coding issues, but I also
    >would like to be told when someone has a
    >problem with me personally before getting
    >slacked off here.

    I don’t have a problem with you personally, I have a problem with the code you write.

    >If I played in your domain,
    >sorry, if this article sucks and every
    >javascript that does not adhere to OO
    >principles sucks, delete 90% of the script
    >outlets on the market.

    Please do not confuse the issue. OO has nothing to do with your, my script, or my critique of your script.

  23. >>Interesting. I cannot remember, but I looked
    >>it up in the css-d archives and it turns out
    >>you’re right.
    >Frankly, I get a lot of such mails, and if
    >I’d have to answer them all I wouldn’t have
    >time for anything else. Besides, at that
    >moment I was very busy with writing my JIR
    >script and getting quirksmode ready for

    Ok, this is more than understandable.

    >>Some time passed, as ALA, same as
    >>takes some time to publish.
    >>No word there, no word of PPK on the list
    >>that he published a version on
    >Now this is untrue. On the same day you wrote your mail to me,
    >I announced on css-d and I explicitly said
    >that it contained a JIR script.
    >So you could have known.

    The same way you could have taken my email about it more serious.
    It is OK for you to not answer the immediate answer-mail to your mail but I should find the mentioning of JIR in the last sentence of the announce email of I get a lot of mails, too.

    The “interesting discussion” you mentioned could and should have happened in the first email then, it would have prevented this article and my script (which is not as bad as you make it depending on how you use it. Granted, certain elements are bad).

    In your article you mention the overuse of
    loops. I agree with the break statement idea and will insert it.
    However I don’t consider invalid XHTML better.

    It’s a matter of what you do, my example works with pages that get generated with random names and IDs (ASP.NET likes doing that), yours assumes I can totally control the HTML, and add an extra attribute that results in invalid xHTML.

    Also, let’s not forget that image replacement of headers is a cosmetic change, it is unnatural for a header to be an image. Hence you should stick to replacing headers for an article only. Your example of 20 headlines in one document would be either a whole book or an extreme overuse of headlines. This is were image replacement fails, the overuse of it (latest CSSZENGARDEN entries prove that).

    As for the alt text displaying, if you read the first comment, this is a known mozilla bug.

    I totally agree with your bit about assumptions, and will test some of my stuff as soon as my screen reader arrives.

    It is a shame that there is no free screen reader on WIN, and that the prices are that high.

    I was enthusiastic about the idea, and released something too fast. Agreed. However you could have emailed me with your concerns and I would have made damn well sure that these changes get implemented here, rather than pointing the finger and publishing your article. I cannot undo what happened.

    There were crappy ALA articles in the past, and every cutting edge idea / article has it’s drawbacks. FIR was the best till Joe Clark proved us wrong.

    Your solutions has invalid HTML, mine has Javascript that needs improvement and may give some screen readers images with alt texts.

    As stated in the article I am willing to constantly update the script, and I see it as an example for other developers to come up with own solutions. The style switcher script here got improved this way aswell.

  24. >The same way you could have taken my email
    >about it more serious.
    >It is OK for you to not answer the immediate
    >answer-mail to your mail but I should find >the mentioning of JIR in the last sentence of
    >the announce email of I get a >lot of mails, too.

    Sorry, but no.

    1) You are responsible for the content of your article, whether I replied to your mail or not.

    2) When you decide to write a major article, you are responsible for doing a literature study to find out whether anyone had tackled this issue before. You did not.

    >As for the alt text displaying, if you read
    >the first comment, this is a known mozilla

    But my screenshot uses IE Windows, not Mozilla.

  25. Ok, fact is that I submitted my article before I have found and read yours. That is the whole problem.

    I was too fast it seems, hey, happens.

    About your screenshot, let’s quote the article:

    “The only users whose experience is negatively affected are those with JavaScript turned on and images turned off. These users will see the text replacement for the image. An exception are Mozilla users — but more on that later.”

    I like reading up on things, and I read my emails in threads. So your “quirksmode released” email didn’t show up in the emails around the original script idea / my fast shot. That’s why I didn’t even know you already had finished a nice script with another solution. I guess I wouldn’t have bothered releasing this one then.

    My enthusiasm was trying something and posting it as an immediate response, to see if we could go from there. You didn’t realise that. A shame, could have saved a lot of hassle now.

    I see the flaws you and others mentioned, I see the flaws in your solution. I see the logic of your theoretical approach, but I still think this here is a good in between solution till we tackled the issue fully.

  26. I must say that sooner or later in the web publishing world this (by ‘this’ I mean ‘this argument’) was bound to happen. Especially with the looser structure that online publishing has vs. the print world.

    I respect both writers, and being an online author myself, I can sympathize with both gentlemen. However, PPK, you are out of line.

    1. Patrick G. is right, your response was emotional and mean spirited. I think you lost a bit of your hard earned respect from the web community with your response. If I were you, I would re-write it. You are coming off as an elitist, which I never thought that you were.

    I have no problem with publishing an article in response and making your points, in fact you should, but do it *professionally*.

    2. If Chris emailed you with his ideas and you ignored him, don’t whine about the fact that he didn’t consult you. He tried to and you ignored him.

    3. There are some really sharp people out there, and everything you write, you feel like it’s immediately open to criticism from the “experts”. To label Chris’ effort as “sucks” is a really unkind thing to do.

    I imagine that Chris put his full effort into the article and I think his intentions were not to “screw up” anyone’s ideas, but to present an article he felt was worth writing.

    Whether he succeeded or not is a different issue. He should’t be personally attacked, especially when you did not know all the facts surrounding the writing of the article, as later pointed out by yourself in this comment thread.

    Lastly, as for ALA’s ability to present JavaScript articles. Maybe for YOU, they don’t help or you don’t find them inspirational or challenging. However, ALA has quite a large and diverse readership. I imagine many people who don’t follow hardcore JS sources enjoy the occasional JS article here, and even find it helpful.



  27. Errors or no errors, this is another “doesn’t quite work for everything” solution to a problem that is already loaded with “doesn’t quite work for everything” solutions. While I appreciate options, I’ll keep my images in header tags for the time being.

    Regarding other comments…

    >> Why not just use the “text-indent:-100px” method which does all this

    Unless there is an enhancement I don’t know of, this fails in Win IE5. It applies the negative indent to the background image and therefore displays nothing.

    >> I use FIR (with visibility:hidden, not display:none), and tell the User Agent that this particular portion of the StyleSheet is only for the eyes of screens

    According to Joe Clarks FIR article ( there’s not much difference between the two. I was also under the impression that screen readers will use screen stylesheets and not aural.

    I briefly flirted with the idea of using classic FIR but width:0; height:0; overflow:hidden; position:absolute; for the span which should work for screen readers (if I am to believe what I’m told) but still fails for CSS on / images off.

  28. Apologies. This is a test to see if html source can actually be rendered.

    headline 1

    <h3 class=”jir” id=”cellar-1.jpg”>headline 1</h3>

  29. In mid-november, I learned of PPK’s JIR attempts. Below is a sample of what I come up with after trial and experimentation with various browsers (both Mac and Windows). It could work in Safari but something misbehave with replaceChild method (!?)

    Image Replacement

    headline 1

    headline 2

    headline 3

  30. >1. Patrick G. is right, your response was
    >emotional and mean spirited.

    Emotional, yes. Mean spirited, no. The worst I say is “Chris Heilmann doesn’t know what he’s doing”, and I back up this statement by facts.

    >2. If Chris emailed you with his ideas and
    >you ignored him, don’t whine about the fact
    >that he didn’t consult you. He tried to and
    >you ignored him.
    >He should’t be personally attacked,
    >especially when you did not know all the
    >facts surrounding the writing of the article,
    >as later pointed out by yourself in this
    >comment thread.

    Beside the point. If you’re writing a serious technical article for an internationally renowned magazine you should do solid research. That research was lacking.

    I do not attack Chris Heilmann as a person, but as a JavaScript coder and author.

    >Lastly, as for ALA’s ability to present
    >JavaScript articles. Maybe for YOU, they
    >don’t help or you don’t find them
    >inspirational or challenging. However, ALA
    >has quite a large and diverse readership. I
    >imagine many people who don’t follow hardcore
    >JS sources enjoy the occasional JS article
    >here, and even find it helpful

    This is not a matter of personal preference. The article contains a bad script, and anyone who implements it because he thinks it’s helpful could have a rude surprise when the script misfires disastrously. Therefore I feel it shouldn’t have been published.

    Please do not make the mistake of thinking my reaction is *just* a personal one. Although I was pretty emotional when writing the article, my JavaScript facts are solid and will stand up to close scrutiny.

  31. I don’t think there are many people doubting your JavaScript is solid. The issue has turned in to one about the way you have handled this affair.

    Although you say that your article is not mean spirited, you continue to use terms such as ‘attack’, ‘butchered’ and ‘I’ll tell you to get lost’. Your piece, as a whole is hostile.

    It is unfortunate that the issues surrounding the ALA article itself have been overshadowed by discussion on how to approach comments and criticisms in general.

    The point that many here are trying to get across is that there is no need for such hostility – it does not helps any one. In fact, it has quite the opposite effect.

  32. PPK, I agree with what Patrick just said. I don’t disagree that the errors were present. QC could have been better on the article.

    It was definitely your handling of the issue though, that has sparked many of the comments above. I still say you could reflect on it a bit and re-write your response.



  33. Hello,

    I would like to share a method of image replacement that does not rely on JS, yet has less problems than FIR. It utilizes the CSS3 ‘content’ property for an arbitrary element.

    h1 {content: url(image.jpg);}

    I posted it to CSS-D in June 2003

    It is also discussed in the article on Nemesis:

    The Nemesis URI is not permanent, so I will provide also a permanent URI on my site mirror:


    1. Independent of JS support
    2. Markup is clean of ‘span’ and other hooks for styles
    3. Screen readers will not render the ‘content’ property, and will read the content of the heading as if nothing ever happened
    4. CSS2 browsers will not parse the ‘content’ property for a heading, and will display text-styled heading as if nothing ever happened.
    5. Code required to specify a heading is really minimal and, imo, elegant
    6. It already works in Opera, and will work in Gecko and Safari once they add support for ‘content’, so it is future-compatible

    best regards,


  34. I think the point has been lost amidst PPK’s arguments.

    As someone who didn’t write an equivalent script or even know about PPK’s script when I first read this article, I was disappointed with it from the start. The code was poorly written and full of errors. It also will not work in many situations in Mozilla and doesn’t degrade gracefully when images are disabled in the browser.

    Seeing a JS article that is so shoddy on a site this big is disappointing. Many, if not most, developers that visit this site assume that the content is top-notch, and rightly so. (Many of the articles here are, especially some of the recent ones with regard to CSS techniques.) If ALA publishes an article that isn’t up snuff, readers who aren’t well-learned in the topic will take it as gospel and you get bad teaching proliferated out to a large audience.

    This bugs me more than anything. The web is chalk full of bad scripts and we really need some quality scripts out there. This script is not one of them.

    One last bit, more of a personal thing though. I don’t think this solution should be done with JS in the first place since it doesn’t offer any advantage over current solutions. But, again, that’s my personal opinion. All I ask is that you publish quality scripts, even if I wouldn’t be one to use them.

  35. PPK -I respect you, but am amazed at your ‘unprofessional reaction’. You have unnecessarily chosen the moral high ground. I am looking for a teacher, one who will guide us through the crazy technical imperfections of web techniques and web browsers and the difficulties faced by programming. You have the capability to teach and teach well. When a teacher approaches with respect, he gains immeasurable esteem. I don’t see the ‘zeldmans’ of this world flinging mud when I do something stupid or imperfect. They sit down and patiently re-explain… and hope that this time the penny will drop. (By the way: when in their shoes I usually chirp “why do I bother!” – not ideal either).

    No one way to Rome: The way we thought about image replacement is different now to six, months ago, last year, next year, whatever. Mobile devices and the publics use of them still have to really come of age. We struggle to understand new concepts all the time and adjust our perception of reality constantly. My cristal ball says we will use sever side sniffers to recognize the device and then serve the documents on the fly with xslt. White papers or protocols will tell us what the device wants to see. Hopefully (I know, I’m being over optimistic) there will be a handful of generic devices and generic xslt files to get get the stuff on da street.

  36. >> Why not just use the “text-indent:-100px” method which does all this

    > Unless there is an enhancement I don’t know of, this fails in Win IE5. It applies the negative indent to the background image and therefore displays nothing

    Can’t say I’d seen that bug reported anywhere and I just tried my site ( on the IE5 test machine at work (IE5 on Windows NT SP6) and it works perfectly.

    That’s not to say there’s not a problem in certain circumstances, but certainly in on my site and on that machine, all works fine.

    Feel free to take a look at the source.

  37. >PPK, I agree with what Patrick just said. I
    >don’t disagree that the errors were present. >QC could have been better on the article.
    >It was definitely your handling of the issue
    >though, that has sparked many of the comments
    >above. I still say you could reflect on it a
    >bit and re-write your response.

    Ah, hell, Tom, maybe you and Patrick are even right, I don’t know any more.

    It’s just that there is so bloody *much* JavaScript trash floating around the Web, and ALA may be turning into the umpteenth JavaScript junkyard, deceiving the innocent newbies who come here for guidance.

    Yes, I feel defensive about my idea. I think it’s important, not in itself but for the fundamental issues it reveals. I’ve never been shy about sharing my ideas, though. Anyone who wishes to extend or criticize it, please go ahead.

    But when someone writes an article about my idea on ALA, of all places, and he *doesn’t even notice* that there are fundamental issues to be considered, or that his script is just plain bad, and his editor doesn’t notice either, I get angry and sad.

    Unjustified, maybe, but human.

    I feel I’m fighting a losing battle for using JavaScript *responsibly*, while dozens of script kiddies mangle it up beyond recognition because they can’t look beyond the wow-factor. And if even ALA actively supports this irresponsible behaviour out of sheer ignorance, what am I to do?

    I lash out. Not particularly constructive, true, but I had to get this off my mind. And I still feel that, though I may have been too harsh on Heilmann, if anything I’ve been too soft on ALA.

  38. When I first learned of, I said “Wow! This is EXACTLY what I’ve been looking for. The guy behind this knows exactly what he’s doing.”

    Now I’ve seen the real guy behind Peter-Paul, you have acted in a manner that no matter how you look at it is unprofessional.

    This may be a lost cause, but I’ll continue anyway.

    Yes, you may be the best javascript coder out there. Your ideas may be truly unique and you may be the guy who pioneers things most of us could only dream about.

    However, there is a trait that commands much, MUCH more respect than simply being an innovator. That, my friend, is humility. In my opinion arrogance will get you nowhere.

    I read the ALA article and agreed with you, the author’s code is not up-to-snuff. I will not use the technique on my site nor do I think Christian is an advanced Javascript developer or quality technical author. These, however are traits that can be developed with practice and time.

    For the technique itself, yes, your code is about as good as it gets for JIR. I would use it in a heartbeat, if I agreed with JIR in the first place.

    The bottom line though, as many have stated, is not your code nor your comments on Christian’s abilities as a Javascript developer or author. The problem here is a serious lack of respect for another individual and the lack of humility that, as I said earlier, commands much greater respect than unique thought.

    I strongly encourage you to take the high road and end the ongoing flame war. Rethink how you’ve worded your article. Everything in there is “my code is better than yours (which sounds very similar to a ‘my daddy could beat up your daddy’ argument I heard on the playground in third grade.”

    Yes, you back it up with facts, but a simple statement (as I think someone commented elsewhere) of “A better option would be to…” would make your article a much friendlier read and I guarantee would receive a much friendlier response from those of us in the development community who enjoy learning from innovators such as yourself.

    Honestly, I have learned a great deal from As soon as I visited, I learned something that I implemented on a client site that very day.

    However, it is very difficult to trust and learn from a person who it is hard for me to respect.

  39. Michael-

    That script looks pretty decent, except it looks like it could cause some memory leaks. You may want to try and stick with local variables when possible and not keep too many references to HTML elements. You run into circular references pretty quick.

  40. How could I answer to PPK’s claims if I didn’t get any? I had totally forgotten that the article is out today. On my evolt articles I get an email when a message comes in, a feature this “forum” doesn’t have.

    I like moose’s solution, it is the correct one and will be a big success in some year’s time.

    But what do you do now, when a client wants image replacement and it should work on IE5, 5.5 and 6?

    I was more insulted by your post than by PPK’s to be truthful. He claimed that the dash in his name is not much of an issue, you tried yourself on sarcasm about it. A kind of neener neener behaviour. PPK doesn’t need anyone defending him, he publishes articles when he thinks there is a need for it.

    I updated the script with some of the improvements asked for here, this is the learning I have taken and the action I have done. Not too good, but a start, and a lot more than just ranting on and blowing the horn of one or the other side.

    Maybe I am not as good an editor as I think I was (I surely released this one too early and we surely didn’t look over it well enough before publishing it). I _do_ know some bits though and I am not a script kiddie as hinted and claimed here.

    Can we keep this in levels that are productive?

    Some articles on ALA were wicked when they came out and make you cringe now. They got updated, that is the whole idea. When DHTML came out, the Dan Steinman site was a killer, now we know much of it was bloated and just not future proof.

    I respect PPK a lot, and I respect a lot of people knowing much of CSS to come, I just wished that instead of bickering here we could just work together on the same problem, hey, I am game. If I am not good enough, I try to improve, if I just hear hostility and unproven accusations, I shut up and do something more productive.

  41. >Ah, hell, Tom, maybe you and Patrick
    >are even right, I don’t know any more.

    >It’s just that there is so bloody *much*
    >JavaScript trash floating around the Web,
    >and ALA may be turning into the umpteenth
    >JavaScript junkyard, deceiving the innocent
    >newbies who come here for guidance.

    1. Nice rewrite. That’s so much better. My respect for you is now intact! 😉 (jk)

    2. To the JS issue: You are mostly correct – and maybe this is straying off topic for this comment thread, not sure. I learned JavaScript by myself starting in 1996-7 and I can’t tell you how many times I got frustrated as a beginner when I went somewhere that had junk code.

    Now as someone who is somewhat considered an “expert” (hate the term) which I really am *not* (trust me), I STILL find the same problem which you allude to when I search for scripts/articles today. In some way the article OR the explanation (or both) fail.

    Unfortunately I think its the nature of the online publishing. But I agree, we *can* hold ALA to a higher standard. I expect, knowing the people behind ALA, that they will learn from this as far as quality control goes.

    Anyway, don’t wanna ramble! Cheers…


  42. PPK’s updated response is much better.

    I’m still a little peeved about his comments about JavaScript in general on ALA because I think the article I wrote with Dan Webb ( is a good use of good JavaScript (and there is some response to this at

    Still, I hope that you take this further and draw it to the attention of the ALA people (it would be good to hear from them on this matter, here or on maybe). Maybe *you* could be the JavaScripter on their editorial board, as you suggest.

    I hope there are no hard feelings.

  43. re: … Heilmann (write it any way you want)

    Sorry Chris… it was my lapsus kalamis.

    :: How could I answer to PPK’s claims if I didn’t get any?

    I meant on his post in ALA. When I first time read all (three days before) his replay were already here. Two days passed but it was totally ignored (looks like that yesterday).

    :: I like moose’s solution *** But what do you do now, when a client wants image replacement and it should work on IE5, 5.5 and 6?

    It is the question of web (web-publishing) understanding (imho): just to use scale-principe and to compare this: IE (x.yy) clients do not see the image but they have no any clue that image should be there – they just see the nice, real(!) heading (written by text and displayed by chosen style (font…)) which could be selected, copied etc… second case is that some other client, with strange browsing attitude (could browsing attitude be called as ‘strange’ at all?) means javascript on and images off doesn’t see the image, doesn’t see the real heading but see that ‘beautiful’ well known alt-image-replacement. So, I would not discuss in the field ‘What if…’ – just which of cases above author, you or anybody else, do prefer (maybe sometimes it depends on site content… maybe not). In moose case also, author do not need to write any of that meaningless warnings as ‘Headings on this site are represented by images…’ etc… means: ‘please do switch this or that on or of…’…

    :: I was more insulted by your post than by PPK’s to be truthful.

    Good. It was the base idea – to push you on some action.

    :: He claimed that the dash in his name is not much of an issue, you tried yourself on sarcasm about it.

    ppk has (c)opyright on his own name of course but has not (neither you) copyright on inappropriate using of any person name in global so, as long as I am protecting his name, I am protecting my own name also or anybody else’s in the future.

    :: PPK doesn’t need anyone defending him***

    The same as above: I do not know him really but I didn’t like the case. My small two cents for better world tomorrow if you know what I mean (I think you do).

    What I also think is that conflict is finished: you have nice attitude and ppk is also back when read your answer. Nobody knew that you really did everything on the correct way (pre-publishing issues) but ppk didn’t know that also:)) so: you forgive him, he forgives you and all ok.

    :: I respect PPK a lot, and I respect a lot of people knowing much of CSS to come***

    Somebody here mentioned that all of this is because you are not one from ‘big five’ (or ten or hundred) well known web-developers… it is not true: I do respect few well known people also (why should not) but I was really shocked when saw moose ideas; I’ve spent a lot of time browsing that site and sites of few of his friends. So fresh, so original… I mean we should respect work – not names only.

    Re: “I was more insulted…” I do apologize to you (so easy always to say that – never late) for your insulation but I can not apologize for my post. If you’d answer on ppk’s post faster, earlier, I’d never comment any article about javascript techniques (real amateur here – maybe just would post the moose solution link). So, Chris, I really want you to accept my ‘beg pardon’ and am sure that you will.

    At the end: I also can not understand people who are ‘abused’ with emotional ppk’s comment: sure that it had to be emotional – he did’t know that Chris wrote to him. At that time, his answer were so human, understandable, adequate… and good that Chris made everything clean.

  44. yes, I just this morning realised that the article has been published, as I spent the whole weekend with my girlfriend watching old Hitchcock movies as the weather was too foul to go out, and she doesn’t have a computer.

    Real life, sorry 🙂

    Generally I like PPKs new article a bit more, he could have taken in account the changes I made to the script on it’s homepage (as stated in the article, the place where changes will happen), but you cannot expect everyone to check all before publishing an article.

    I also cringe a bit at
    “Worse, by publishing such articles ALA actively promotes a sloppy, irresponsible coding style that sharply diverges from the accessibility, web standards and structural coding the magazine purports to promote.”

    As adding an invalid attribute is not web standards, sorry.

    One of the big advantages of my version (and I would gladly include the loading of the image bit that makes PPKs version superior – albeit I won’t until he agrees that I can do that) is that the markup does not need any specialities. This may sound anal about xHTML, but there is a reason for it:

    I was also doing this script as a client needed it. They want it, yes, they want graphical headlines, and search engines should find the headlines, and they want them all in IE 5.5+. Furthermore they want WYSIWYG editing in the CMS, which means we get after we run the tagsoup created by WYSIWYG through and XSLT sheet, clean HTML, but we have no chance to add ids or, for that matter, even invalid attributes. Reading the content of the H1 and generating an image file name from it is not an option either, as we are working in 12 languages, including special characters which could easily result in headlines getting the wrong image.

    Now, this is a big project, big money, and everything the client wants.

    One example where my script DOES make sense. Not everything the article claims it does, but it works.
    The client can happily edit their articles and they get an extra field to add all the images.

  45. >Generally I like PPKs new article a bit more,
    >he could have taken in account the changes I
    >made to the script on it’s homepage (as
    >stated in the article, the place where
    >changes will happen), but you cannot expect
    >everyone to check all before publishing an

    Chris, I’m trying hard not to pick on you, but your comment is such a perfect handle for this important lesson that I couldn’t resist posting it.

    Publishing on a Serious Webzine: lesson 1

    If you publish so much as a word on a serious webzine like ALA, you *cannot go back on it*. Your article has to be perfect before you submit it.

    Chris, if you’d written your article anywhere else than on ALA I probably wouldn’t have noticed it, and if I had I’d have ignored it. I wrote my article solely because you chose to publish it on ALA (and because its editors chose to let it stand).

    I exclusively focus on your ALA article because ALA is a highly visible and respected webzine, and by default your article becomes highly visible and respected, too. It is this visibility and respect that I object to, and not the mere fact that you wrote your article.

    The next time you publish anything on a serious webzine, please make sure that it is perfect *before* submitting it, not after.

  46. I’m going to respond briefly to some comments made in this forum, and then I’m going to close the forum as it no longer serves as a calm or useful place for professional discussion of the ideas described in the article.

    Saturday morning I saw PPK’s first post ( and did three things in response:

    1. Article edit: linked to PPK’s current personal site, Quirksmode, per his suggestion.

    2. Article edit: corrected the spelling of PPK’s name, i.e. added the hyphen between Peter and Paul. PPK used to be an ALA author; I know how his name is spelled and would likely have caught the error if I had edited the article.

    3. Internal staff discussion: discussed PPK’s underlying point with the ALA staff and invited J. David Eisenberg ( to join us as a technical editor in the areas of XML and the DOM — to which David graciously consented.

    David is a programmer, the author of a fine O’Reilly book on SVG, a co-founder of The Web Standards Project, and was a technical editor on my second book, Designing With Web Standards. His ALA bio page lists many of his past articles for A List Apart; more will be listed as soon as they are reformatted. David’s participation will help ensure that content quality in his area of expertise remains as high as ALA’s content quality in other areas.

    I considered these three actions an appropriate response: one that would make things better going forward. Anything else — such as responding in kind — I considered inappropriate.

    When we receive negative criticism, whether it’s discreetly handled in a private email message or posted publicly, and whether it’s delivered tactfully or not, we ask ourselves if there is merit to the complaint. If there is merit, we ask ourselves what we can do to improve. And then we take the necessary actions. And that is all that is needed.

    ALA tends to attract a considerate, professional crowd. Intelligent comments in the forum can be as useful and illuminating as the article to which they pertain. That is why we host a discussion forum.

    Our discussions rarely get hijacked and derailed, but if they do get bent out of shape, all we can do is shut them down. This forum is now closed.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA