Why do anchor pseudo-classes a:link, :visited, :hover, :active need to be in correct order?
There is a detailed description here:
http://meyerweb.com/eric/css/link-specificity.html
It is related to CSS specificity.
Citing from there:
All of them can apply to a hyperlink, and in some cases, more than one will apply. For example, an unvisited link can be hovered and active at the same time as it's an unvisited link. Since three of the above rules apply to the hyperlink, and the selectors all have the same specificity, then the last one listed wins. Therefore, the "active" style will never appear, because it will always be overridden by the "hover" style. Now consider a hyperlink which has been visited. It will always and forever be purple, because its "visited" style beats out any other state, including "active" and "hover."
This is why the recommended order in CSS1 goes like this:A:link
A:visited
A:hover
A:active
BTW W3 Schools is not the best resource for formal definitions. You are better off going to the source, at w3c. For example, it is not "vitally important", but it is recommended.
Why must a:hover come after a:link and a:visited in the CSS?
Because there is a priority order.
if hover was before visited, then hover wouldn't get ever applied, because it would be "forever" overwritten by visited style (if it has been really visited), that was applied after.
Same goes for :active (mouse down) - if it's defined before hover, then hover will always overwrite :active(mouse down)
Makes sense?
On the other hand, this is just "conventional rule" - it is not forced. If anyone wants to have :visited higher priority, overriding :hover/:active - you are free to do so - it simply would be just unconventional
And lastly, it is not only order that plays the role of style priority.
Elements that are more explicitly defined have higher priority.
Styles that are !important
will have higher priority than explicitly defined styles.
Explicitly defined styles with !important
and set last will have "ultimate" priority.
To question "Why would you want to use these to override styles? Wouldn't it be better just to make styles in your CSS file correctly ordered?" - Reason to use overrides by more explicit definition and !important priority overrides comes handy when you use large css/theme/bootstrap, that you haven't created and you have to quickly override/change some stuff... These dirty overrides come as a quick/cheap (not very pretty) solution.
.theBad:active {
color: red;
}
.theBad:hover {
color: green;
}
.theGood:hover {
color: green;
}
.theGood:active {
color: red;
}
<a href="#" class="theGood">the Good</a> - this will turn red on mouse down
<br />
<a href="#" class="theBad">the Bad</a> - this poor little thing will not
<!--#ordermatters, The Ugly is lurking somewhere in the shadows-->
Why does .foo a:link, .foo a:visited {} selector override a:hover, a:active {} selector in CSS?
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...
Exam 70-480: CSS order of anchor elements
As in CSS and HTML5 links can be standardized to follow color coding which helps user to understand which are link is visited and which is not.
technically, 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.
Hope this helps.
Why bother with the L in the LVHA link styles?
Not all anchor tags necessarily have a href
attribute, so they're not all links. Presumably the :link
pseudoclass does not apply to anchor tags without a href
.
Why does the hover pseudo-class override the active pseudo-class
yes this is expected behavior,
lets take a look at another example. just adding two classes,
<ul>
<li class="item first">item</li>
<li class="item">item</li>
<li class="item">item</li>
<li class="item">item</li>
<li class="item last">item</li>
</ul>
here the class first also comes together with the class item.
but if we declare our css in the wrong order that would not give the wanted behavior
.first { background: blue; }
.item { background: red; }
as you can see, the last matching selector will be used.
it is the same as your example, no mather what is more logic,
the 2 pseudo-classes are concidered equal, thus the same rules apply
the last matching defenition wins.
edit
pseudoclasses are equals, it is the one defined last that wins! here is a jsFiddle that proves my point :link defined after :hover, :link wins (test) so, your statement of :hover overriding :link is wrong, its just the same like with :active, its all about the order.
Why don't link pseudo-classes work on class selector?
Your selectors don't work because you currently select an a
tag inside an element of class .btn
, because the space in selectors means selecting a descendant. As it is written now, it would suggest a markup like this:
<div class="btn" >
<a href="http://google.com">Why doesn't this work?</a>
</div>
But for <a class="btn" href="...">...</a>
You should use:
.btn {position:relative; width:auto; background:#2c96c9; color:#fff; cursor:pointer}
a.btn:link {color:#fff; text-decoration:none}
a.btn:visited {color:#fff; text-decoration:none}
a.btn:hover {color:#000; text-decoration:none}
a.btn:active {color:#000; text-decoration:none}
What's the point of the :link pseudo-class?
The a:link
selector lets you set the styles on <a>
tags that actually link somewhere.
Bare <a>
tags without an href
attribute are traditionally used as markers in a document; setting the location to document.html#foo
will jump you to wherever <a id="foo">
is in the document. It is, after all, called an "anchor" tag for a reason.
Traditional HTML may look something like this:
<h2>Navigation</h2>
<a href="#ch1">Chapter 1</a>
...
<h3><a id="ch1">Chapter 1</a></h3>
<p>It was the best of times...</p>
Subsequent HTML standards let you use the document.html#thing
syntax to jump to any element with the attribute id="thing"
, but it wasn't always the case.
Is there a reason to use a instead of a:link or a:visited in my stylesheet?
This is of course assuming there would never be a reason to use an
<a>
tag without anhref
value. Maybe that's a mistaken assumption.
It depends on your project. Strictly speaking, that is a mistaken assumption, as not every <a>
element needs to have a href
attribute. Indeed, it's still not required in HTML5 to specify href
for every <a>
. Chris Blake and Ryan P mention named anchors, and I'll add that while the name
attribute for <a>
has been made obsolete as of HTML5, named anchors are still rife and will continue to be, simply by legacy and tradition.
That said, going forward, authors are recommended to use id
attributes and not named anchors to designate document anchor fragments.
Also, <a>
elements that lack href
attributes but have onclick
attributes for JavaScript are a mess. Even if you insist on using onclick
to bind events, for the sake of graceful degradation you should at least point it somewhere using href
.
But to make things simple, let's assume that you won't be writing <a>
elements without href
attributes.
With this in mind, going back to the CSS selectors, there are two important points to consider:
Are they the same?
No, the selectors a
and a:link, a:visited
are not strictly equivalent. I'll quote a previous answer of mine on this topic:
The selector
a
should match any<a>
elements, whilea:link
only matches<a>
elements that are unvisited hyperlinks (the HTML 4 document type defines hyperlinks as<a>
elements with ahref
attribute). Nowhere does it state in either specification thata
should automatically translate toa:link
or vice versa.
In other words, in HTML, a:link, a:visited
(in CSS1) is strictly equivalent to a[href]
(in CSS2 with an attribute selector) or a:any-link
(new in Selectors level 4), rather than a
. Note that it doesn't matter whether the attribute has a value or not, as long as it is present the pseudo-classes will match, hence [href]
. Note also that this is true for all current standards of HTML, and I believe this includes HTML5, since as mentioned above href
is not a required attribute in any existing spec.
Just bear in mind, that other languages may define completely different semantics for :link
and :visited
— it just so happens that they coincide with an equally specific selector in HTML, which is covered next...
Specificity
This is a huge gotcha: a
is less specific than either a:link
or a:visited
, which is a very common source of specificity problems that are particularly evident when applying styles to a
, a:link
and a:visited
separately. This then leads to all kinds of !important
hacks to get around a lack of understanding of specificity.
For example, consider this CSS:
/* All unvisited links should be red */
a:link {
color: red;
}
/* All visited links should be slightly darker */
a:visited {
color: maroon;
}
/* But no matter what, header links must be white at all times! */
body > header > a {
color: white;
}
This doesn't work as expected, because a:link
and a:visited
(what I call generalized rules/selectors) are more specific than body > header > a
(what I call a specialized rule/selector), so header links will in fact never be white:
/* 1 pseudo-class, 1 type -> specificity = (0,1,1) */
a:link, a:visited
/* 3 types -> specificity = (0,0,3) */
body > header > a
Now the first thing that comes to mind for most CSS coders is to throw in !important
, trumping specificity altogether:
body > header > a {
color: white !important;
}
But that gets you all kinds of bad rep, right? So let's not do that.
Selectors level 4 gives you not one, but two solutions to this specificity problem. These solutions, new as they are, aren't supported in Internet Explorer and Microsoft Edge Legacy (the UWP/EdgeHTML/not-Chromium one), but thankfully there is a third solution that works in Internet Explorer 7 and later, which is a[href]
, the attribute selector I mentioned above.
1. The :any-link
pseudo-class
:any-link
has some history behind it which you can read in my answer to this question, but practically speaking, :any-link
serves as a catch-all for :link, :visited
. Its main purpose is to eliminate selector duplication, and for that reason there is in fact an equivalent in the form of :is(:link, :visited)
.
You can use a:any-link
in your specialized rule to match the specificity of the generalized a:link
and a:visited
rules, thereby allowing it to override them:
a:link {
color: red;
}
a:visited {
color: maroon;
}
/* 1 pseudo-class, 3 types -> specificity = (0,1,3) */
body > header > a:any-link {
color: white;
}
2. The :where()
pseudo-class
:where()
also has some history behind it, but essentially it's an analogue to :is()
with the exception that it zeroes out the specificity of its argument. See my answer to this question for an in-depth guide to how it works.
You can wrap the :link
and :visited
pseudo-classes in :where()
s to remove their pseudo-class specificity, thereby allowing them to be overridden by the specialized rule:
/* 1 type -> specificity = (0,0,1) */
a:where(:link) {
color: red;
}
/* 1 type -> specificity = (0,0,1) */
a:where(:visited) {
color: maroon;
}
/* 3 types -> specificity = (0,0,3) */
body > header > a {
color: white;
}
3. a[href]
(for older browsers)
Fortunately, if you need to support older browsers, an attribute selector is as specific as a pseudo-class. This means you can use a[href]
to mean both/either a:link
and/or a:visited
, and not run into specificity issues because they are equally specific!
/* 1 attribute, 3 types -> specificity = (0,1,3) */
body > header > a[href] {
color: white;
}
So which selector(s) to use?
This is all still incredibly subjective, but I follow these personal rules of thumb:
Apply to
a
styles that do not depend on the state of a link (i.e. as long as it's a link will do).Apply to
a:link
anda:visited
styles where it does matter whether a link is visited or not.Taking into account the specificity problems mentioned above, do not mix any declarations between both
a
anda:link
/a:visited
rules. If I need to apply the same property to both states somewhere, but I already have it in separatea:link
anda:visited
rules, I'll use one of the 3 options above to avoid specificity problems.
For example, here are the link styles I used in my site's Coming Soon page prior to its launch:
a {
text-decoration: none;
transition: text-shadow 0.15s linear;
}
a:link {
color: rgb(119, 255, 221);
}
a:visited {
color: rgb(68, 204, 170);
}
a:hover, a:active {
text-shadow: 0 0 0.5em currentColor;
}
a:focus {
outline: thin dotted;
}
/* ... */
footer a:link, footer a:visited {
color: rgb(71, 173, 153);
}
The text-shadow
transition is defined for all a
elements, regardless of whether they are visited or not, because the transition only takes effect when one of them is moused over and clicked (corresponding to the a:hover, a:active
rule).
Now, I want visited links to have a slightly darker shade than unvisited links, so I put the colors in separate a:link
and a:visited
rules. However, for some reason, I want footer links to appear the same color whether they're visited or not.
If I use footer a
, I'll run into the specificity problems described above, so I choose footer a:link, footer a:visited
instead. This was for legacy reasons (as you'll see below, I originally posted this in 2012!), but of course it can be shortened to footer a:any-link
. However, the specificity-matching principle applies all the same.
Hopefully my advice helps you get a handle on the mess that is link styles.
Related Topics
How to See the CSS Files Loaded in a Page in Google Chrome
How to Align About the Colon in Each Line of Text Like Movie Credits Often Do
Use CSS to Hide Contents on Print
Why Are Inline-Block Elements Not Displayed Correctly in Internet Explorer 8
How to Inline Less Stylesheets
CSS Styling - How to Put These Two Div Boxes Adjacent
How to Change the Button Color When It Is Active Using Bootstrap
Seek to Specific Keyframe in CSS3 Animation
How to Get Div Height 100% Inside Td of 100%
How to Remove Clear Button ( 'X' Button ) from Ie10 Textboxes in Compatibility Mode
How to Prevent Division When Using Variables Separated by a Slash in CSS Property Values
Xmlns W3 Url for Svg Spec Now Throwing Error in Chrome
Combine Calc() with Attr() in CSS
CSS Grid - Repeatable Grid-Template-Areas