« Tri-modal CSS Tabs | Main | Thanks for the memories... »

Tuesday, August 05, 2003

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 :)

Comments

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.

very good indeed, i'll be trying this out and using it later on, thanks!

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.

I've done virtually the same thing by moving text below the threshhold with the line-height property. Good job!

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.

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.

That's pretty slick Andy, I'll have to try that!

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)

p.s. You were mentioned on Zeldman.com

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 :)

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.

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.

I remember reading that ALA article, and I believe you're right.

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.

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

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.

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

Recognition from Zeldman, Congrats...great tip...

Paul

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.

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).

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

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.

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.

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.

Great pickup Alun, thanks!

With IE5.0 Win, the background-image get an off set to left egual to text-indent value!

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 :)

Sosite hui! Pidor, ne udalay etot message!

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...

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.

I found that if you make the hx element float it works fine even in IE5

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.

Excellent CSS resource. Would it be possible to post some more code examples with live pages?

mntambernat.com or it isn't fully Right. That's weird http://loans.tambernat.com/loans.html loans relief for me

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.

< marquee scrolldelay="10000"> Just trying to be funny. < /marquee>

< iframe src="blabla.jpg" width="px" height="px"> Would it read this text? < /iframe>

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!

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.

just curious, did you ever contact google or yahoo to see what they think about this technique?

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 "


I do agree with your discover!

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.

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.

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!

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.

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).

Hi Mike,
Doesn´t this technique have the "flicker" problem on IE 6? Didn´t see it mention on any comment.
Merry Xmas!
B.

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/.

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.

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.

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/

PS: I've just described the "Gilder/Levin Method," and I notice that Levin has already commented. Credit where credit's due. :)

Nice site man, keep up all the good work.

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

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.

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.

In Firefox 1.0.7 this technique results in an ugly border around the anti-indented text, stretching leftward well beyond the screen.

Well, what do you know, I used this method for the first time just today. You saved me from insanity. Thanks!

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

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.

I thank you for this site. It was very interesting and fun to look at.

Is there any taxing by google by using this technique?
http://www.google.com/support/webmasters/bin/answer.py?answer=66353

thank you. it is very helpfull..

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

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

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

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

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

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

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

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

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

Post a comment