Accessible Image Replacement
Ever since Todd Fahrner made famous his Fahrner Image Replacement (Doug Bowman explains) technique, people that use screen reading devices have been complaining that it doesn't work as they had hoped.
Now, I do not have a screen reader, nor have I ever used one, but I believe that I have found a better image replacement technique that actually works for people with screen reading software.
The goal is to keep the text "visible" to the browser, but hidden to the user. That is to say, the text must not be able to be seen by the person viewing the website, but still has to be there.
What I have been doing is this:
<div id="replaceText">
Some text goes here...
</div>
With this kind of CSS attached to it:
#replaceText {
text-indent: -9000px;
background: url(bg.gif);
.... }
Now, what this does, is move the text 9000 pixels to the left (or "before", depending on in which direction your text is written), such that is it no longer viewable in the parent container.
The text is "still there", however you cannot see it. The background image shines through proudly, and the screen reader will happily read your extremely negatively-indented text, disregarding the background!
Update: Thanks to my friend "Vavoom"'s usage of his screen-reader, the above-mentioned technique is now verified to work with the JAWS screen-reading software.
Note: IE5 on Windows has a problem with the technique, where it negatively indents the text and background image. To fix this, place the image replaced div inside of an absolutely positioned parent element. Just experiment, there are other workarounds for this bug :)
THANK YOU!!!
I have been looking at the image replacement solution and finding it attractive, but entirely too problematic.
I found your suggestion and just tried it, viewing it both on the monitor, and with monitor off using JAWS, it works like a charm!
Fantastic. Thank you.
Posted by: vavroom | Tuesday, August 05, 2003 at 10:17 PM
very good indeed, i'll be trying this out and using it later on, thanks!
Posted by: p | Monday, August 11, 2003 at 02:09 PM
Uh-oh. This technique could kick your site off search engines. As well as you can throw in text meant for screen reader users, you could throw in some keywords or some other text fooling search engines. Hiding stuff like that the way you describe is used by SEOs (Search Engine Optimizers) since years with questionable results. I strongly suggest not to use it.
Posted by: Oliver | Monday, August 11, 2003 at 03:09 PM
I've done virtually the same thing by moving text below the threshhold with the line-height property. Good job!
Posted by: Jonathan | Monday, August 11, 2003 at 03:15 PM
Oliver:
That's definitely true. I should contact people at google or yahoo to see what they think.
Jon:
Kick ass website! That line-height idea sounds real useful, especially with very wide elements where the text-indent value would be really high, and a quick line-height value would be easier to write.
Posted by: Mike | Monday, August 11, 2003 at 03:21 PM
As a further tweak for use with headers, etc., how about:
<h1 style="background-image:url(header.gif);">
Header replaced with image
</h1>
<h1>Header without image</h1>
h1 {
background-image: none;
}
h1[style] {
background-repeat: no-repeat;
text-indent: -100em;
}
That way, if you want a h1 without replacing the text, simply use it as normal; if you want to use an image, stick it directly in the h1 tag, and the CSS selector for h1[style] will apply the text-indent to only h1 tags with style attributes.
Posted by: Andy | Tuesday, August 12, 2003 at 08:55 AM
That's pretty slick Andy, I'll have to try that!
Posted by: Mike | Tuesday, August 12, 2003 at 11:24 AM
This technique is not accessible for me. I mostly surf with images disabled and sites that use FIR are sometimes really plain:
http://levin.grundeis.net/files/20030812/images_off.jpg
However, there is a solution:
http://levin.grundeis.net/files/20030809/alternatefir.html
(which sadly relies on an additional span)
Posted by: Levin | Tuesday, August 12, 2003 at 07:24 PM
p.s. You were mentioned on Zeldman.com
Posted by: Paul Watson | Wednesday, August 13, 2003 at 05:40 AM
Rob, can you post some code?
Paul, I know!!! I seriously thought I was going into cardiac arrest when I saw it. I met Jeffrey just this past year in Albany, NY, and had him sign my PowerBook!
Levin:
Its tough not using a span tag AND have the technique work when images are turned off (CSS on). I think everyone and their brother is trying to find that holy grail, and when they do, you can bet that it'll be all over the net within minutes :)
Posted by: Mike | Wednesday, August 13, 2003 at 10:36 AM
Cool technique, IE does have some trouble rendering unordered lists (and a bunch of other "regular" HTML tags lol), so before I make a decision, I always check my page out in Lynx to see if the layout sans-CSS works or not.
Posted by: Mike | Wednesday, August 13, 2003 at 02:07 PM
In reference to the posible search engine problems, I think its important to note that most search engines ignore CSS.
In fact that is one reason to switch to CSS based design - your code is more content based and hence easier to search and index.
Thats one thing that A List Apart and others have pushed about it..
Search engines tend to analyse content for spam, rather than a technique. Hence loads of keywords is flagged, but not a short description.
Again, as most search bots ignore CSS there should be no problem with this technique in modern search engines.
Posted by: Greg | Friday, August 15, 2003 at 09:50 AM
I remember reading that ALA article, and I believe you're right.
Posted by: Mike | Saturday, August 16, 2003 at 07:57 PM
Your technique with the text-indent fails in IE5.5, at least for me. I have a DIV containing an H1 and a P, with the background image set. The DIV height and width dimensions are the same as the background image, and I used your text-indent: -100ems to move the text out of the way. Unfortunately, in IE5, I get a blank space where the DIV should be. I'm still tweaking it - if I come up with a solution, I'll post it here.
Posted by: Bob | Tuesday, August 19, 2003 at 09:44 AM
Bob:
Thanks for checking in IE 5.5, I think that's one of the few browsers I have left to use this technique with.
Can you post a screenshot (or a link to a screenshot lol)? I'd like to see what it looks like and if anything could be done.
Mike
Posted by: Mike | Wednesday, August 20, 2003 at 10:54 PM
Remember that IE.5.5 has a broken box model and so you will need to use the workaround.
Incidently I use a variation on the above for headings. I use:
#replaceText h1 {
text-indent: -100em;
overflow: hidden;
background: url(bg.gif);
line-height: size of bg.gif;
}
Works on IE5.5, IE 6.0, NS 6.2 , NS 7, Safari 1.0.
Sadly it breaks on IE5.2 on the Mac, but as Safari and Mozilla are both available on the Mac I'm not too concerned about this.
Posted by: Aled | Monday, August 25, 2003 at 09:10 PM
Aled:
I really like the combination of using the line-height and the negatively indented text.
I'm going to be incorporating both from now on ;)
Also, I was asked to write an article for Made for All regarding accessible image replacement techniques, and I think that I'll mention the line-height idea as well as the text-indent one as ideas to conquer image replacement.
I'll post back here when its all said and done with to see what everybody thinks.
Mike
Posted by: Mike | Tuesday, August 26, 2003 at 12:19 AM
Recognition from Zeldman, Congrats...great tip...
Paul
Posted by: Paul | Wednesday, September 10, 2003 at 12:56 PM
Sorry for the delay in the screen cap. I hadn't been back here since I posted my comment above. However, Aled's reminder about the box model in IE5 (something I almost never remember) should fix the problem.
Posted by: Bob | Tuesday, September 23, 2003 at 03:19 PM
Of all of the FIR image replacements I've seen, I believe this is the best one. You can also make them be links!
CSS:
h1 { background: your_bg_info; height: 30px; text-indent: -100em; overflow: hidden }
a { display: block; height: 30px }
<h1><a href="/">Home Page</a></h1>
Tested Opera 5/6/7 and NS 6/7 (NS 7 wasn't actually displaying the bg image, but then again, it only displays some of the images some of the time for me. Link still worked, though).
Posted by: chris | Friday, October 24, 2003 at 12:05 PM
Great call! Some people take the method at face-value, and forget that you can pretty much do whatever you want with the code to make it fit your design.
Consider if you are replacing a logo on the right side of your page... instead of doing a negative text-indent, just take the negative sign off and push your text off to the right. Or increase the value to something like -10,000 lol.
Oh, and I realized that there's really no need to keep the overflow rule in there, if you're moving the text a virtual "foot" off the screen anyway, there's no chance your user will ever see it. Overflow is what chokes IE5 for the Mac and some other browsers, so see if that helps.
Mike
Posted by: Mike | Friday, October 24, 2003 at 01:46 PM
The text-indent technique doesn't work in IE5.01 unless position: absolute; and overflow: hidden; are added. this breaks it in 5.5 though.
Posted by: Seth Thomas Rasmussen | Tuesday, March 23, 2004 at 12:16 PM
After having worked with the -text-indent method, FIR, and LIR as image replacement methods, I have found that applying the negative Text Indent is a successful method for replacing text with an image on most browsers. Like all workarounds, there is no concrete solution, and the largest drawback currently with this method is that with images turned off, the stylistic information is lost (the "alt text" if you will). However, despite this shortcoming, this method of image replacement requires not only the smallest amount of changes to existing CSS, but is the most compatible with preexisting layouts and designs.
Thank you very much for this wonderful article.
Posted by: Jakob | Wednesday, April 07, 2004 at 06:08 PM
For the record: The negative text-indent method will work in IE/Win 5.01, *if* absolute positioning or floating are used on the containing element. Otherwise, IE5.01 will correctly outdent the text, but will carry the background-image with it - even if the background image is aligned right instead of left.
An alternative solution is to use an internal span and apply the text indent to that, and the background-image to the container element. However, this defeats one of the main advantages of this technique.
Posted by: Alun David Bestor | Monday, May 10, 2004 at 03:41 AM
Great pickup Alun, thanks!
Posted by: Mike | Monday, May 10, 2004 at 02:07 PM
With IE5.0 Win, the background-image get an off set to left egual to text-indent value!
Posted by: gianluca | Wednesday, June 09, 2004 at 05:49 AM
I'm aware of that problem Gianluca, but thanks. According to other people, absolutely positioning the parent element seems to fix it, but I've not tried that method so there are no guarantees :)
Posted by: Mike | Wednesday, June 09, 2004 at 09:21 AM
Sosite hui! Pidor, ne udalay etot message!
Posted by: Mike | Saturday, June 12, 2004 at 04:51 PM
I have enhanced this technique with a little Javascript extra - it nearly works .If you follwo the link below and look at it with images enabled and also disabled you will see what I mean.
http://www.webpusher.ie/imageswap/
There is a flash of the link text while the page is loading and then one the .onload event triggers the Javascript will add the -9999px text-indent to the li elements.
I'm still working on it, I think its time for some serious 'out of the box' thinking...
Posted by: Mark | Wednesday, June 23, 2004 at 12:42 PM
Just surfed in and found this really interesting place here. A lot of good stuff for everybody.
Go on like this and i will surely visit your site again sometime.
Posted by: suzi | Friday, August 13, 2004 at 05:42 AM
I found that if you make the hx element float it works fine even in IE5
Posted by: Sius | Thursday, October 07, 2004 at 06:14 PM
In regards to Google and concerns using this legitimate method, how about the following...
1. Using an external CSS file set the ROBOTS.txt on your server to prevent SE robots from accessing the file.
If you aren't concerned that JS may be switched off then...
2. Use Javascript to write the reference line to the external CSS file - as Google doesn't read in JS that will help.
3. Combine the above methods and use an external JS file, the ROBOTS.txt will prevent either the CSS or JS file being read in should Google ever start reading JS.
Posted by: Jon | Wednesday, October 27, 2004 at 07:11 AM
Excellent CSS resource. Would it be possible to post some more code examples with live pages?
Posted by: Adil | Friday, February 04, 2005 at 09:48 AM
mntambernat.com or it isn't fully Right. That's weird http://loans.tambernat.com/loans.html loans relief for me
Posted by: loan | Tuesday, February 15, 2005 at 11:44 AM
I made a rather bizarre discovery. If you include Tantek Celik's IE5.0/Windows Band Pass Filter in the head of the document - without actually importing an extra css file - IE5.0 on Windows applies your image replacement techique as intended, i.e. there is no need to position the containing element absolutely or to float it, or to make use of an extra span.
Strange.
I've only tested this on my PC, so I'm concerned that maybe I have made an error somewhere. My current (rather crappy) homepage makes use of this technique. Check it out with IE5.0 on Windows and see if the image replacement works.
Posted by: Will Bolton | Sunday, March 27, 2005 at 02:58 PM
< marquee scrolldelay="10000"> Just trying to be funny. < /marquee>
< iframe src="blabla.jpg" width="px" height="px"> Would it read this text? < /iframe>
Posted by: gaby de wilde | Wednesday, April 13, 2005 at 10:24 AM
Will, you are absolutely correct! Just tried it out on a site I'm working on, whose background image on an H1 wasn't showing in IE 5.0. Adding the Band Pass filter makes it work. Tested with Browser Cam. Thanks!
Posted by: Josh Lavin | Wednesday, April 20, 2005 at 10:04 AM
Thanks for this, Mike and everyone. I've been messing about with this a bit and it seems to work in IE 6/5.5/5.01, FF 1.0.3, NS 7.2 and Opera 8 in Windows. I've not had chance to test it in *nix or Mac yet, I may use BrowserCam. I've used the following:
display: block;
text-indent: -100em;
overflow: hidden;
line-height: 30px;
background: url('image.png') top left no-repeat;
I've been writing a PHP function that will create images based on text inputted automatically and display it, a demo is here: http://www.stillbreathing.co.uk/experiments/aire/demo/. Thanks once again.
Posted by: Chris | Saturday, May 07, 2005 at 05:16 AM
just curious, did you ever contact google or yahoo to see what they think about this technique?
Posted by: tom | Tuesday, May 17, 2005 at 05:04 PM
loan: "Cash Advance Payday Loans: Yes The Rates Are Higher!By: Greg Ford "
Loans: "Unsecured Loans: The Lesser Known Sibling Of Secured Loans By: Aditya Thakur "
Loan: "5 Signs You Need a Personal Loan By: Holly Bentz "
Posted by: loan | Monday, June 06, 2005 at 09:59 PM
I do agree with your discover!
Posted by: wonglee | Saturday, July 16, 2005 at 10:16 AM
Thanks, I got this working on my site, in combination with Will's discovery.
On another note, has anyone ever used this method:
http://www.tjkdesign.com/articles/tip.asp
It's another out of the box, yet very simple solution. Focuses more on the image tag, and the styling of it. Allows you to make use of the title and alt tags of images also... whatever you may want to use those for. ;-) Also shows text when images are disabled.
Posted by: Jade | Saturday, July 23, 2005 at 12:04 PM
This 'works' but is still incredibly ugly in my opinion. It solves a problem no doubt which is realistically the biggest yardstick in terms of success but it also creates problems. We can use all the hacks we want but our pages will never be truly universally accessible without some major standards changes and communication between some of the key players in this farce.
Posted by: Tristan Gray | Wednesday, August 10, 2005 at 07:59 AM
this fails in Opera 8 as far as i can see.
the horizontal scrollbar indicates that the browser 'thinks' the page really is 9999px wide.
hate to think what happens if they print!
Posted by: Matthew | Monday, September 05, 2005 at 12:32 PM
With the new Firefox 1.5 beta, you'll need overflow : hidden is using this technique, otherwise you'll get the selected outline showing, which is quite ugly.
Posted by: James | Tuesday, September 20, 2005 at 08:58 AM
Actually that solution doesnt solve the problem if you have your list items indented in your list at all, you still get lines outside of your designated box.
Sadly the only real solution to this problem is to put a SPAN, I, or B tag (there are others, these are common) inside of your link, and set that to
display : none;
AND (thank you firefox 1.5) because ie6 applies some irresolvable margins to items when they are display:none, we now get to use the star html hack to set those spans to display: inline; text-indent:-9999px; (as it used to be).
Posted by: drew | Tuesday, November 15, 2005 at 10:45 AM
Hi Mike,
Doesn´t this technique have the "flicker" problem on IE 6? Didn´t see it mention on any comment.
Merry Xmas!
B.
Posted by: Bruno | Monday, December 12, 2005 at 08:37 PM
Hi!
Thought I'd let you know about my technique of making a css background image clickable - details at http://www.davss.com/webdesign/logo/.
Posted by: David Sadowski | Thursday, January 19, 2006 at 04:28 PM
Why even use this technique? I have always prefered to use “display” .
eg:
<h1 class="logo"><span>text</span></h1>
h1.logo {background….}
h1.logo span {display: none;}
Yes is adds another line in the css, but its less text overall, and then the text is not visable at all in a css enabled browser but is there for screen readers.
Posted by: pogdesign | Saturday, January 21, 2006 at 09:00 PM
Pog - That technique does not work in screen readers because they actually pay attention to CSS. If a block of text is hidden using CSS, then it won't be read to the user. That's why text-indent is effective because it is still "displayed" on the screen so it will still be read.
The original FIR technique used display: none; to accomplish a similar feat, however if you check Doug Bowman's post on Fahrner Image Replacement, you'll see that Doug has a disclaimer at the bottom saying that it doesn't work for screen reader usage, thus defeating the purpose altogether.
Posted by: Mike Rundle | Sunday, January 22, 2006 at 01:45 AM
Nice technique! I especially liked the line-height refinement. Unfortunately, I decided not to go with it, because it's potentially buggy on some of my target browsers. I settled for an empty span inside the element. First I styled the element itself to look a little like the text I was replacing it with, giving it fixed width/height and "overflow: none". This let me position the semantically-bankrupt span, with an appropriate background, over the top of it. I even put an inside the span to make the page validate. (Hey, I'm already filthy—what's a little more dirt?) In the end it works without any browser hacks in all of my target browsers, and has the added bonus that with images off/CSS on, the page remains aesthetically acceptable.
To an extent I agree with Tristan (no relation, honest): we've got an ugly problem which demands an ugly solution, although yours is the most elegant and semantically pure I've seen. Hopefully, future CSS specifications will include properties to help replace a text element's representation with an image, while leaving the text intact for screen-readers/image-free browsers: "image-representation: url(image.png) 100px 40px" or something similar.
In the meanwhile, this site is great for those looking for more information about image-replacement techniques:
http://www.mezzoblue.com/tests/revised-image-replacement/
Posted by: Jordan | Saturday, February 04, 2006 at 12:08 PM
PS: I've just described the "Gilder/Levin Method," and I notice that Levin has already commented. Credit where credit's due. :)
Posted by: Jordan | Saturday, February 04, 2006 at 12:13 PM
Nice site man, keep up all the good work.
Posted by: penis enlargement | Monday, April 10, 2006 at 03:12 AM
so many techniques.. i wonder which is the best one, for aural devices as well as for users who disable images (do they still exist btw?)
btw what about the technique of doug with using the z-index to put the text behind the bg-image? i reckon, it can become visible when u resize the text-size with ur browser, but then again, u just dont have to put it so big, right :p? u can't do good for users with images disabled, ppl who resize the fontsize with their browser AND aural devices
Posted by: geert | Wednesday, April 26, 2006 at 03:24 PM
This is pretty lame. CSS visibility, should only affect visual visibility. Screen readers should read everything with visibility:hidden as well. So this hack is working around bugs in screen readers.
Posted by: Carewolf | Sunday, April 30, 2006 at 11:24 AM
Like Will, I also made a pretty bizarre discovery about IE5.0/Win. It seems that adding empty style-tags in the end of the document right before the /BODY-tag makes the method work in IE5.0. Well at least in my case, this might not work in other scenarios.
Like this: (the line break needs to be there to make it work)
<style type="text/css">
</style>
Anyway, this is not the best possible way to make it work since style-tags should only be used inside HEAD-element.
Posted by: Timo | Thursday, May 18, 2006 at 07:11 AM
In Firefox 1.0.7 this technique results in an ugly border around the anti-indented text, stretching leftward well beyond the screen.
Posted by: Karma Debugger | Tuesday, June 13, 2006 at 09:30 PM
Well, what do you know, I used this method for the first time just today. You saved me from insanity. Thanks!
Posted by: Nicole | Friday, June 16, 2006 at 06:04 PM
http://www.blinklist.com/buyfemaleviagra/ buy female viagra
http://rollyo.com/buyviagraprofessio/ buy viagra professional
http://rollyo.com/buydiscountviagra/ buy discount viagra
http://www.blinklist.com/buy%20viagra%20canada/ buy viagra canada
Posted by: buyviagraonline | Monday, February 25, 2008 at 04:44 AM
Just wanted to take time to thank you for this nice site. I found it by accident but I will return for sure. Lots of helpful information that I found very interesting. Thanks again.
Posted by: florida rentals | Monday, March 10, 2008 at 08:38 PM
I thank you for this site. It was very interesting and fun to look at.
Posted by: florida rentals | Monday, March 10, 2008 at 08:40 PM
Is there any taxing by google by using this technique?
http://www.google.com/support/webmasters/bin/answer.py?answer=66353
Posted by: Bjarni | Tuesday, March 11, 2008 at 05:50 PM
thank you. it is very helpfull..
Posted by: software_developer | Friday, March 14, 2008 at 12:49 PM
http://letsgo.kz lets go kz
http://gamecheatsnew.blogspot.com new game cheats
http://newsspyware.blogspot.com news spyware
http://topcelebrityblogs.blogspot.com top celebrity blogs
Posted by: letsgo | Wednesday, March 26, 2008 at 04:42 AM
http://mycelebrity.wordpress.com my celebrity
http://celebrityclub.wordpress.com celebrity club
http://celebrityhotnews.wordpress.com celebrity hot news
http://sexycelebrity.wordpress.com sexy celebrity
Posted by: celebritymy | Thursday, March 27, 2008 at 09:04 AM
http://mycelebrityclub.blogspot.com My celebrity club
http://topcelebrityblog.blogspot.com top celebrity blog
http://blogcelebritystars.blogspot.com blog celebrity stars
http://bloggercelebrity.blogspot.com blogger celebrity
Posted by: mycelebrity | Thursday, March 27, 2008 at 03:35 PM
http://topcelebrityblogs.blogspot.com top celebrity blogs
http://jessica-alba-fan-blog.blogspot.com jessica alba
http://jessica-simpson-fan-blog.blogspot.com jessica simpson
http://jennifer-lopez-fan-blog.blogspot.com jennifer lopez
Posted by: topcelebrity | Friday, March 28, 2008 at 10:06 AM
http://scarlett-johansson-fan-blog.blogspot.com scarlett johansson
http://britney-spears-fan-blog.blogspot.com britney spears
http://parishiltonfanblog.blogspot.com paris hilton
http://linsey-lohan-fan-blog.blogspot.com linsey lohan
Posted by: topcelebrity | Friday, March 28, 2008 at 11:11 AM
http://nicole-kidman-fan-blog.blogspot.com Nicole Kidman
http://eva-longoria-fan-blog.blogspot.com Eva Longoria
http://50-cent-fan-blog.blogspot.com 50 Cent
http://akon-fan-blog.blogspot.com Akon
Posted by: 50 Cent | Saturday, March 29, 2008 at 04:27 PM
http://justin-timberlake-fan-blog.blogspot.com Justin Timberlake
http://gwen-stefani-fan-blog.blogspot.com Gwen Stefani
http://kylie-minogue-fan-blog.blogspot.com Kylie Minogue
http://madonna-fanblog.blogspot.com Madonna
Posted by: Madonna | Saturday, March 29, 2008 at 04:57 PM
http://linkin-park-fan-blog.blogspot.com Linkin Park
http://christina-aguilera-fan-blog.blogspot.com Christina Aguilera
http://pamelaandersonfanblog.blogspot.com Pamela Anderson
http://robbie-williams-fan-blog.blogspot.com Robbie Williams
Posted by: Linkinpark | Sunday, March 30, 2008 at 10:40 AM
I was using the FIR. After mindlessly hacking at a more complex solution for ie5.5, this seems to work beautifully. I've seen a buddy using this before but doubted it's simplicity.
Dude!!!
sean
Posted by: Berger | Wednesday, April 30, 2008 at 10:58 PM