Why does the hover pseudo-class override the active pseudo-class
Asked Answered
P

8

25

The title basically says it all.

Suppose I have an element which I want to change color on :hover, but while clicked, I want it to switch back to its original color. So, I've tried this:

a:link, a:visited, a:active {
    background: red;
}
a:hover {
    background: green;
}

As it turns out, this doesn't work. After a lot of head-scratching, I realized that the :hover state was overriding the :active state. This was easily solved by this:

a:link, a:visited {
    background: green;
}
a:hover {
    background: red;
}
a:active {
    background: green;
}

(I could combine the 1st rule with the 3rd one).

Here's the fiddle: http://jsfiddle.net/V5FUy/


My question: is this the expected behavior? As far as I understand this, the :active state should always override the :hover state, since the :active state will almost always be accompanied with the :hover state.

Priest answered 22/9, 2011 at 0:10 Comment(6)
This is the (unfortunately) expected behavior. I'm not privy to the origins of this oddity, but it has been this way as long as I can remember (going on 10+ years, now). That said, I think it remains this way because browsers want to remain consistent with eachother. The fact that all browsers respect this order means that the code you write will work in all browsers. I don't disagree with your assessment that :active should always override :hover, though.Kain
@Kain - Thanks. You seem to be the only one here that's understanding my question.Priest
Maybe it has to do with the order in which :active and :hover were added (to CSS1 and CSS2, respectively)... We are seemingly in history territory at this point, and not programming.Goodsized
@JosephSilber I think the confusion is you are thinking of :hover and :active as being mutually exclusive. In reality an active anchor link has both pseudo classes when you hover. So it's getting styled by the first line and overwritten immediately afterwards. Here is an example using explicit classes linkAlfons
Here's a related question I answered with my iPhone on a day out: #7372232Centrosymmetric
For those who struggle to remember the proper ordering of pseudo classes related to a tag in a style sheet is - LoVe before HAte. Link -> Visited -> Hover -> ActiveTabor
P
14

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.

Puckery answered 22/9, 2011 at 0:40 Comment(3)
You seem to all be missing the point here. You all understand that :hover always overrides :link, even though it's still a link when you hover. Because everybody understands that if you applied a style to the :hover state, you are not interested in the original state. The same logic should apply to the :active state...Priest
As i said, 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 (jsfiddle.net/kVLEZ) so, your statement of :hover overriding :link is wrong, its just the same like with :active, its all about the order.Puckery
For those who find it difficult to remember the proper ordering of pseudo classes related to a tag in a style sheet is - LoVe before HAte. Link -> Visited -> Hover -> ActiveTabor
E
4

The active state must be declared after the hover state, in your CSS you're clumping together the active state before the active state so it's not being triggered.

If you state the proper order of operation it works, like below, it works fine.

a.noworks:link, a.noworks:visited {
    background: red;
}

a.noworks:hover {
    background: green;
}

a.noworks:active {
    background: red;
}

So, to answer your question, yes this is the expected behavior.

Here is the order of operation:

a:link
a:visited
a:hover
a:active
Erythrocytometer answered 22/9, 2011 at 0:34 Comment(2)
You seem to all be missing the point here. You all understand that :hover always overrides :link, even though it's still a link when you hover. Because everybody understands that if you applied a style to the :hover state, you are not interested in the original state. The same logic should apply to the :active state...Priest
The links follow an order of operation, you can't overwrite something out of order. Predefined conditions have to be met for the order of operation to function. 1. Is it a link? if yes, apply said color. 2. Has it been visited? if yes, applied said color. 3. Is the link being hovered? Apply said color. 4. Has the link been clicked (activated)? If yes, apply said color. You can't break out of that sequence, otherwise it would make the whole link styling process moot. It's like driving a car without first starting it.Erythrocytometer
L
2

Because in the first code you defined :hover after you defined :active, so :hover "overwrote" :active. In the second, it's the other way around, :active overwrites :hover.

Laurentium answered 22/9, 2011 at 0:32 Comment(2)
You seem to all be missing the point here. You all understand that :hover always overrides :link, even though it's still a link when you hover. Because everybody understands that if you applied a style to the :hover state, you are not interested in the original state. The same logic should apply to the :active state...Priest
You're missing the point. Since you defined :link first, :hover overwrites it. If you put :hover first then it won't work.Laurentium
J
0

EDIT:

Sorry, I misunderstand the question.

Basically when you are in active state (with a mouse pointer) you are actually in hover state too. So based on CSS rules it would read the last one in stylesheet.

When you hover over a link and hold down the mouse key It's like this if we take pseud classes as normal classes :

<a class="active hover"></a>

So if your css was

.active{color:green}
.hover{color:red}

it would apply red

but if your css was

.hover{color:red}
.active{color:green}

It would apply green

From W3C

a:link    { color: red }    /* unvisited links */
a:visited { color: blue }   /* visited links   */
a:hover   { color: yellow } /* user hovers     */
a:active  { color: lime }   /* active links    */

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.

Jonathanjonathon answered 22/9, 2011 at 0:20 Comment(3)
You're still missing the point. Read the last line of the question!Priest
You are once again missing the point. I know that while being in the :active state I'm also in the :hover state. I've clearly stated that in my question. What I'm trying to understand is this: Why do these 2 pseudo-classes share the same specificity weight? In my opinion, :active should always override :hover precisely because you always :hover while being :active!!!!Priest
You seem to all be missing the point here. You all understand that :hover always overrides :link, even though it's still a link when you hover. Because everybody understands that if you applied a style to the :hover state, you are not interested in the original state. The same logic should apply to the :active state...Priest
Q
0

This is how it works, and I'll try to explain why. As we know CSS will continue searching the document when applying styles and apply the style that is most specific to the element.

Example:

li.betterList { better list styling here }

Is more specific and will overwrite

li { list styling here }

And these Puesdo selectors are all considered the same specificity and thus the last line will overwrite the previous one. This is confirmed by the note on W3Schools

Note: :active MUST come after :hover (if present) in the CSS definition in order to be effective!

you can also throw this CSS on your jsfidle and watch it overwrite since they are the same specificity

.works {background: red}
.works {background: green}
Quittor answered 22/9, 2011 at 0:48 Comment(0)
A
0

This is the expected behavior in so far as most people always place the :hover pseudo-class at the end of the group of rules.

Order of declaration matters with pseudo-classes (see more here: http://reference.sitepoint.com/css/pseudoclasses), so the final rules get precedence, as with other rules in CSS.

For most people, I think the desired behavior:

a:link {
  ⋮ declarations
}
a:visited {
  ⋮ declarations
}
a:hover {
  ⋮ declarations
}

Since the :active is not so useful it is left out... or combined with a:link and a:visited... and then it is overridden by a:hover

W3C spells it out here:

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.

http://www.w3.org/TR/CSS2/selector.html#dynamic-pseudo-classes

Even W3schools gets this one right:

Note: a:hover MUST come after a:link and a:visited in the CSS definition in order to be effective!!

Note: a:active MUST come after a:hover in the CSS definition in order to be effective!!

http://www.w3schools.com/css/css_pseudo_classes.asp

Alcot answered 22/9, 2011 at 1:2 Comment(0)
E
0

I think you should at least consider the flow of User Interaction on links (or buttons).

Usually,

  1. :link has always been the default (untouched),
  2. Then when a User points to the button, then that is where :hover comes into play.
  3. Once a User points to the link or button, then he/she will click, that is where :active comes in.

That is the standard sequence of how we interact with links (or buttons). With the exception of :visited, where the result is only obvious when the User has previously pressed the link.

It would be really helpful if you keep in mind the mnemonic: ' L o V e H A t e ' when dealing on links (except for :visited, which doesn't work for buttons).

However, if you really want to do an override, say, you want to change the color of a link that was already visited on active state, you can do something like:

a:visited:active {
     color: red;   
}

But the bottom line is, avoid changing the standard sequence if it's not necessary.

Eulogy answered 22/9, 2011 at 4:21 Comment(0)
P
0

You can have the :active pseudo-class override the :hover pseudo-class regardless of the order of declaration by using the :not() selector.

a:link, a:visited, a:active {
    background: red;
}

a:hover:not(:active) {
    background: green;
}

This way, the :hover selector is triggered only when the :active selector is not.

Propaganda answered 25/2, 2021 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.