Notes on suggesting link styles

There are many answers given to the questions of the form "How should I suggest that ---- links be ----?" Most of them have some serious problems in current browsers or could in future browsers. Below I explain a way that both avoids problems in existing browsers and is forward-compatible. Unlike much of the theoretical advice I give, this is intended to be usable advice when the document is complete (it's not complete yet, though). Still, use it at your own risk.

The theory

The correct way to suggest styles for links is complicated because of both browser bugs and differences between CSS1 and CSS2. In CSS1, there were three link pseudo-classes, all of which were mutually exclusive: :link, :visited, and :active. None of these pseudo-classes applied to any elements other than links. CSS2 left :link and :visited as the link pseudo-classes (and still mutually-exclusive), but it moved :active into the dynamic pseudo-classes. CSS2 also added two new dynamic pseudo-classes: :hover and :focus. In CSS2, these dynamic-pseudo classes can match any element, although in future versions of CSS, :active and :focus may be restricted to matching elements that take user input (as defined by a CSS property).

Common mistakes

Before I show the correct way to write selectors that match link elements, I will show a number of common mistakes:

a
While this may work well in many cases, it has two theoretical problems and one practical one. First, it matches named anchors in HTML in addition to links. Second, it doesn't match XML links. Third, it doesn't override user styles in some browsers (which???).
a:link (when used to match all links)
Since the :link and :visited pseudo-classes are mutually exclusive, this does not match any visited links.
a:link, a:visited
This needlessly restricts the link elements being matched to links created using HTML's a element (as opposed to XML links).
:link, :visited, :active
In browsers that implement CSS2, the :active selector alone could match any element the user clicks on, rather than only matching links.
:hover (to match hovered links)
In browsers that fully support CSS2 or future versions, this could match any elements in the document tree, not just links. (Similarly, a:hover is bad because it will match named anchors in addition to links.)
:hover:link, :hover:visited (to match hovered links)
While this is correct in theory, it doesn't work correctly in MSIE4 or MSIE5 for Windows or MSIE4 or MSIE4.5 for Mac (??). These browsers use only the last pseudo-class and ignore the rest (something not possible in any version of CSS).
a:active or a:hover (or variants)
Selectors such as these have the problem that they have the same specificity as a:link or a:visited, and therefore the order of the rules matters. This can be confusing, especially since MSIE is buggy and treats (some of??) them as if they had higher specificity.

The best way

The following are the best selectors to use for matching various types of links. However, I do not advise grouping them. (By that, I mean using a selector such as :link:active, :visited:active, :link:hover, :visited:hover.) Grouping could cause the entire rule to be ignored if a browser supports one part of the selector and not another, since browsers should ignore the entire rule if they don't understand a part of the selector. Furthermore, some browsers will allow only the color property to differ between links, and I haven't carefully tested suggesting that other properties are different for different types of links.

My demonstration document shows this method in use. (Because it suggests text-decoration, it does not show up correctly on Opera. See below.)

[1] This will not work on a pure CSS1 browser that supports :active. However, I know of no such browsers. (One could match active links in such a browser with a:active. Such a selector has the disadvantage that it could also match named anchors in CSS2 browsers.)

Why this is best

Here's how the following browsers will deal with the above suggestion. Note that I haven't tested every possible combination of things on every browser, so there may be bugs I don't list below. If Eric Meyer's CSS support mastergrid says that a browser doesn't support :active, the only thing I have tested is that my demonstration file works correctly for visited and unvisited links.

A perfect CSS1 browser (none exist)
Will deal with the :link and :visited rules correctly. It will not deal with the first type of rules for active links, but it can deal with the second. If there were any such browsers in the real world, one might want to use a:active to match active links. However, all browsers that support a:active will handle a :link:active rule correctly.
Browsers that don't support :active, :hover, or :focus
Since these browsers do not support active, hover, or focus selectors in any way, the rules work as well as possible since the unsupported selectors are properly ignored.
Opera 3.5x[2]; Opera 3.60
Since Opera does not support active, hover, or focus selectors in any way, the rules work as well as possible since the unsupported selectors are properly ignored. Link colors do not work reliably on Opera 3.60 when some other properties, such as text-decoration or border are suggested on links. That is, if the text-decoration property is given, then the text-decorations get the correct color but the text does not. However, if the border property is given, then the border gets the correct color (importantly, when the border-color is left at its default), but the text-decorations and text do not. Suggesting borders for links causes many other elements to have borders. Opera also incorrectly allows :link selectors to match visited links for all (?) properties except color.
NN 4.x
NN 4.x does not support active, hover, or focus at all, so it's similar to Opera 3.x in many ways, and the rules work as well as possible since unsupported selectors are ignored. However, in Netscape any property except color (others? I didn't try them all...) given in a rule with selector :link or :visited will match both visited and unvisited links.
A perfect CSS2 browser (none exist); Mozilla[2]
Will work exactly as desired.
Windows MSIE 4.0x; Windows MSIE 5.0
WinIE 4.0x and 5.0 use only the last pseudo-class that they understand, and ignore the rest. This is why the rules :link:hover, etc., must be in that order, and why the rules containing :link:focus must come before rules that override them when they are treated as :link. Both support :hover and :active only on links (so that they are incorrectly "more important" in the cascade than :link and :visited). (The definition of :active used is somewhat strange: links match :active when they have the keyboard focus (either because they are being clicked or were just clicked or because the user got to them by keyboard navigation). Netscape browsers define active links as those on which the mouse is currently depressed.)
Macintosh MSIE 4.0x (???)[2]; Macintosh MSIE 4.5[2]
MacIE 4.5 (does 4.0x also??) incorrectly allows :link to match visited links. Other than that, it behaves just like WinIE 4.0x and 5.0.
Macintosh MSIE 3.0x[2]
Windows MSIE 3.0x
The body of the demonstration document has green text and the links are red (does the visited link work?). IMO, IE3 can be safely ignored at this point. It handles CSS so badly that one can't do anything in CSS if it must work correctly on IE3.

[2] The demo file has not been tested on this browser.

Note (2002-08-21): this document is now cited in an article by Bill Mason, which has some updated testing results.


Valid HTML 4.0!

(Back to CSS, David Baron)

LDB, dbaron@dbaron.org, 1999-09-05, 1999-10-24, 1999-11-07, 1999-11-17, 2000-01-11