Why does .foo a:link, .foo a:visited {} selector override a:hover, a:active {} selector in CSS?
Sample code: http://jsfiddle.net/RuQNP/
<!DOCTYPE html>
<html>
<head>
<title>Foo</title>
<style type="text/css">
a:link, a:visited {
color: blue;
}
a:hover, a:active {
color: red;
}
.foo a:link, .foo a:visited {
color: green;
}
/* A possible fix */
/*
.foo a:hover, .foo a:active {
color: 开发者_JS百科red;
}
*/
</style>
</head>
<body>
<div class="foo">
<a href="http://example.com/">Example</a>
</div>
</body>
</html>
What I was expecting:
The link would appear red on hover.
What I get:
The link appears green on hover.
Questions:
- Why does the
color
defined in.foo a:link, .foo a:visited
selector override the one ina:hover, a:active
? What's going on? - I understand that I can fix it and get what I expect by uncommenting
the commented code. However, I want to know how can we correct the
.foo a:link, .foo a:visited
selector such that it does not override thecolor
defined ina:hover, a:active
?
If I understand http://www.w3.org/TR/CSS21/cascade.html#specificity properly (Thanks, BoltClock), this is the specificity table for the various selectors in the code.
a:link - 0 0 1 1
a:visited - 0 0 1 1
a:hover - 0 0 1 1
a:active - 0 0 1 1
.foo a:link - 0 0 2 1
.foo a:visited - 0 0 2 1
So, the style defined for .foo a:link
overrides the style for a:hover
when both link
as well as hover
pseudo-classes apply to an A element of class foo
.
Similarly, the style defined for .foo a:visited
overrides the style for a:hover
when both visited
as well as hover
pseudo-classes apply to an A element of class foo
.
When you first started with CSS, you might have learned about the LoVe-HAte mnemonic for the order in which to specify link selectors (a:link
, a:visited
, a:hover
, a:active
). Have you ever wondered why this mnemonic was chosen?
Well, there's a note in the spec on how the link and dynamic pseudo-classes are treated when multiple rules using all of them apply to the same element, which explains why you need to set link selectors in that order:
Note that the A:hover must be placed after the A:link and A:visited rules, since otherwise the cascading rules will hide the 'color' property of the A:hover rule. Similarly, because A:active is placed after A:hover, the active color (lime) will apply when the user both activates and hovers over the A element.
Anyway, the point I'm trying to make above is that all four pseudo-classes, being pseudo-classes, have equal specificity. Everything else about specificity applies. In this case, out of a bunch of equally specific selectors, the last rule is applied. When or how each pseudo-class is triggered is never relevant.
Now, the simple introduction of the .foo
selector causes your second set of link/visited rules to override your first set of link/visited styles and the hover/active styles, forcing links in elements with that class to always appear green until you add hover/active styles with the .foo
selector.
Sorry if my answer seems stitched-up or slipshod by the way, I'm typing this on my iPhone right now and it's pretty hard to think out here...
This is how I understand it. All these pseudo classes have same specificity, so the pseudo class written at last wins. Now what do pseudo-classes :link, :visited, :focus, :hover, :active
do? Let us see one by one.
a: link{color: red}
tells the user agent to color the anchor element red in any state. Run the following script:
a:link {
color: red;
}
<a href="www.stackoverflow.com">Go to stackoverflow </a>
The anchor element is colored red in the following states if and only if the link is unvisited,
- Unvisited
- hovered
- Focused(Tabbed)
- Active(Clicked)
So, a: link{color: red}
tells the user agent to give red color to anchor element in all of the above states. Now let's compare it with a:hover
pseudo-class. Run the following script
a:hover {
color: red;
}
<a href="www.stackoverflow.com">Go to stackoverflow </a>
The anchor element is colored red in the following states,
- hovered
- Active(clicked)
We see that both :link
and :hover
pseudo classes are capable to define the hover
state -- So if you assign these two pseudo-classes to a particular element then the one mentioned at last in the css file wins. This is the reason we say :link
will override :hover
when the former is mentioned below the later. The same concept holds for other pseudo-classes. I'd like to give list of what every pseudo class do.
a:link {...}
sets the following states of an unvisited link
- Focused(Tabbed)
- hovered
- Active(Clicked)
link
state will override every other state.
a:visited {...}
sets the following states of a visited link:
- Focused(Tabbed)
- hovered
- Active(Clicked)
a:visited {...}
will override every other state except:link
if and only if the link has been visited.Note that visited means it must be considered visited as per user agent's cache. E.g. a website visited 10 days ago might not be in user agent's cache then it'd be technically considered unvisited.
a:focus {...}
sets the following states for both visited and unvisited links:
- Focused(Tabbed)
- hovered
- Active(Clicked)
a:focus {...}
overrides:hover
and:active
states.
a:hover {...}
sets the following states to both visited and unvisited links:
- hovered
- Active(Clicked)
a:hover {...}
overrides:active
state
a:active {...}
sets the following states for both visited and unvisited links:
- Active(Clicked)
To fix it, put the .foo ...
selector first and add !important
to the color value for the other link/visited selector, like this:
a:link, a:visited {
color: blue;
}
a:hover, a:active {
color: red !important;
}
.foo a:link, .foo a:visited {
color: green;
}
The reason that the .foo a:link, .foo a:visited
selector overrides the other selector no matter where you put it is that because .foo a:link
is more specific than a:link
. (ditto for :visited
.) So the .foo ...
selector will always override the a:link,a:visited
selector because it has a parent class name, so it's more specific.
(Also read @BoltClock's answer about LoVe - HAte - that's part of the problem.)
精彩评论