Outline property for image-replaced links
In the previous article about the annoying outline, I introduced you the JavaScript based solution. After a few days, Nathan Smith came with the much more elegant outline: none; trick. The question remains, how should we apply it in a way not to confuse a user browsing with a keyboard?
Why does all this happen?
If we shift text somewhere far to the left side, with the Phark image-replacement – the text-indent: -9999px; trick, a content box is also stretched. Ouch!
Negative indentation will not remove the text node from a document flow, like for example what position: absolute; would do. A link must be set to display: block; so we can click on the area, surrounding the link text. This means that it should occupy the whole available parent element area.
What do we want to do here, exactly?
- Remove text form a link and replace it with a background-image
- Remove the outline border when an image-replaced link is clicked
- Keep the outline border when an image-replaced link is focused
- Control dimensions of the outline border
The replacement
First, the well known image-replacement trick:
a { background: url("cool_image.gif"); text-indent: -9999px; }
a:visited { background: url("cool_image_visited.gif"); }
a:hover,
a:focus { background: url("cool_image_hover.gif"); }
Remove the outline
We shouldn’t remove the outline completely for the a element, because we are then falling into a trap to confuse a keyboard users. What we should do, is to apply the rule only if we are sure a site is navigated with a mouse. The only way we can detect mouse with CSS is pseudo-class :hover. If something is going to be clicked, it must be hovered first, right? Right. We add the a:hover { outline: none; }:
a { background: url("cool_image.gif"); text-indent: -9999px; }
a:visited { background: url("cool_image_visited.gif"); }
a:hover,
a:focus { background: url("cool_image_hover.gif"); }
a:hover { outline: none; }
Control the outline area
Now, if you hover and click, there’s no outline border, but if you focus it with a keyboard, the outline remains, but is stretched all the way to the left. Fortunately, the overflow: hidden; will do the trick. So, the full set of rules is like follows:
a { background: url("cool_image.gif"); text-indent: -9999px; overflow: hidden; }
a:visited { background: url("cool_image_visited.gif"); }
a:hover,
a:focus { background: url("cool_image_hover.gif"); }
a:hover { outline: none; }
Thinking about the different scenarios is the only way to do the CSS.

9 Comments
I don’t recommend the outline: none; technique. Simply adding overflow: hidden; solves this spilling over of the focus halo. As I mentioned in Nathan Smith’s article.
For me this makes perfect sense for a solution. overflow: hidden; stops this happening, and is easy to understand and apply to other methods.
I haven’t seen the halo appear on :hover, only on :focus, or “onmousedown". So adding outline: none; to that seems pointless.
Removing this halo effect breaks usability, especially with keyboard navigation, as tabbing to links doesn’t show the halo of which is currently active.
Sidenote: Why do you quote your background images? It’s optional, and breaks support for IEmac. Although it’s a deprecated browser, those extra bytes aren’t needed.
Comment (#) by trovster — 20th January 2006.
Why don’t we just ask Mozilla to fix it since it’s the only browser that is rendering it wrong?
Comment (#) by Craig — 20th January 2006.
As I commented on Nathan’s article, take care to hide the
overflow:hiddenrule from IE5/Mac as it will hide the entire element. For example, your entire masthead above the navigation is mysteriously missing in IE5/Mac.Comment (#) by Jon Aldinger — 20th January 2006.
I didn’t read your last article, but it’s nice to know there is an easy way to remove that outline. While in most cases, I think it’s perfectly appropriate to have a dotted outline around the clicked link; there has been times when I wished I could get rid of it.
As for the actual implmentation, placing the outline:none on the :hover pseudo class sounds silly. It’s not the hover that causes the outline, it’s the click. What a weird implementation, sounds like a bug to me.
For the record, I did play around with this just to verify it is indeed :hover that needs the value and not the :active pseudo class…I’ve always got to try it myself ;)
Comment (#) by Justin Perkins — 20th January 2006.
I see no problem in removing the active and focus default borders so long as they are re-styled in a way that is obvious to the user. After all we remove the default underscore on links without a second thought.
I have several demos on my site that show how to remove the dotted borders in FF and IE, which also allow the introduction of non rectangular, non-overlapping links.
Comment (#) by Stu Nicholls — 20th January 2006.
You make a good point, that we don’t want to alienate people that are using the keyboard for navigation. If we hide that outline, alternative means of showing active links should be provided. For now, I’m just leaving the outline on my sites. I just thought people might want to be aware of the ability to hide it, if absolutely necessary.
Comment (#) by Nathan Smith — 21st January 2006.
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 then the text is not visable at all in a css enabled browser but is there for screen readers. Its also less code overall, because you dont have to include any uncessary javascript.
Comment (#) by pogdesign — 22nd January 2006.
Pogdesing, the
display: none;technique acctually prevents screen readers to access text.Comment (#) by marko — 22nd January 2006.
great article!
i was looking for a way to do that, exactly like you shown right here. but i just got one problem doing that.
well. i’m changing my website to a tableless code looking for a better accessibility too.
as you can see on my website (http://konb.org) the “hit area” for my links are on the word only. and if using a “display: block” there, the hit area is available on the entire width of menu (not just over the words)
does anyone have an idea?
i’m sorry if you cant understand my english
thank you anyway
Comment (#) by pablo dias — 24th January 2006.
Sorry, the comment form is closed at this time, but if you have anything to say, please send me a message.