为什么:hover伪类会覆盖:active伪类

25

标题基本上已经说明了一切。

假设我有一个元素,我想在 :hover 上更改它的颜色,但是当被点击时,我想让它切换回其原始颜色。因此,我尝试了以下代码:

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

事实证明,这种方法不起作用。在经过激烈思考后,我意识到 :hover 状态会覆盖 :active 状态。以下方法可以轻松解决此问题:

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

我可以将第1条规则与第3条规则结合起来。

这里是示例:http://jsfiddle.net/V5FUy/


我的问题是:这是预期的行为吗?据我所理解的,:active状态应该始终优先于:hover状态,因为:active状态几乎总会与:hover状态一起使用。


1
这是(不幸地)预期的行为。我不知道这种怪异行为的起源,但据我所记,它已经存在了10多年。话虽如此,我认为浏览器希望保持彼此的一致性,这就是所有浏览器都遵循这个顺序的原因。所有浏览器都尊重这个顺序的事实意味着您编写的代码将在所有浏览器中运行。尽管如此,我不反对您的评估,即 :active 应始终覆盖 :hover。 - Brendan
@Brendan - 谢谢。你似乎是唯一一个理解我的问题的人。 - Joseph Silber
1
也许这与 :active:hover 被添加的顺序有关(分别添加到 CSS1 和 CSS2 中)... 目前我们似乎处于历史领域,而不是编程领域。 - Zach Snow
@JosephSilber 我想你现在感到疑惑的是你认为:hover和:active是互斥的。实际上,当你悬停在活动的锚链接上时,它同时具有两个伪类。因此,它会先按第一行进行样式设置,然后立即被覆盖。这里有一个使用显式类的示例 link - J-Bangin'
这是我在外出时用iPhone回答的一个相关问题:https://dev59.com/u2s05IYBdhLWcg3wPPWB - BoltClock
对于那些难以记住样式表中与 a 标签相关的伪类正确顺序的人来说,它是 - LoVe before HAte。Link -> Visited -> Hover -> Active - RBT
8个回答

14

是的,这是预期行为。

让我们看另一个例子。只是添加两个类:

<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>

这里类first也与类item一起出现。但如果我们以错误的顺序声明CSS,则无法获得所需的行为。

.first { background: blue; }
.item { background: red; }

正如您所看到的,最后匹配的选择器将被使用。与您的示例相同,无论哪个更合理,两个伪类都被视为相等,因此适用相同的规则,最后匹配的定义获胜。

编辑

伪类是相等的,定义在最后的那个会获胜!这里有一个 jsFiddle 证明了我的观点:链接定义在 :hover 后面,:link 获胜 (test) ,因此,您对 :hover 覆盖 :link 的说法是错误的,它与 :active 一样,都与顺序有关。


1
你们似乎都没有理解重点。大家都知道:hover会始终覆盖:link,即使在悬停时它仍然是一个链接。因为每个人都明白,如果你应用了一个样式到:hover状态,那么你就不再关心原始状态。同样的逻辑也应该适用于:active状态... - Joseph Silber
3
就像我所说的,伪类是相等的,定义在最后面的伪类会胜出!这里有一个 jsFiddle 证明了我的观点,当 :link 定义在 :hover 之后时,:link 会胜出(http://jsfiddle.net/kVLEZ/)。因此,你关于 :hover 覆盖 :link 的说法是错误的,就像 :active 一样,这完全取决于顺序。 - Sander
对于那些难以记住样式表中与 a 标签相关的伪类正确顺序的人来说,它是 - LoVe before HAte。Link -> Visited -> Hover -> Active - RBT

4
活动状态必须在悬停状态之后声明,在你的CSS中,你把活动状态和活动状态混为一谈,因此它无法被触发。如果你按照正确的操作顺序来声明,则会正常工作,就像下面这样。
a.noworks:link, a.noworks:visited {
    background: red;
}

a.noworks:hover {
    background: green;
}

a.noworks:active {
    background: red;
}

所以,回答您的问题,是的,这是预期的行为。

以下是操作顺序:

a:link
a:visited
a:hover
a:active

你们似乎都没有理解重点。大家都知道:hover会始终覆盖:link,即使在悬停时它仍然是一个链接。因为每个人都明白,如果你应用了一个样式到:hover状态,那么你就不再关心原始状态。同样的逻辑也应该适用于:active状态... - Joseph Silber
链接遵循一定的操作顺序,您不能按顺序覆盖某些内容。必须满足预定义条件才能使操作顺序生效。1.它是一个链接吗?如果是,则应用所述颜色。2.它是否已被访问?如果是,则应用所述颜色。3.链接是否正在悬停?应用所述颜色。4.链接是否已被点击(激活)?如果是,则应用所述颜色。否则,您无法打破该顺序,否则整个链接样式处理过程将变得无意义。这就像在没有先启动汽车的情况下驾驶汽车。 - Andres Ilich

2
因为在第一段代码中,你先定义了:active,然后定义了:hover,所以:hover“覆盖了”:active。在第二个例子中,情况正好相反,:active覆盖了:hover

你们似乎都没有理解重点。大家都知道:hover会始终覆盖:link,即使在悬停时它仍然是一个链接。因为每个人都明白,如果你应用了一个样式到:hover状态,那么你就不再关心原始状态。同样的逻辑也应该适用于:active状态... - Joseph Silber
你没有理解要点。因为你先定义了:link,所以:hover覆盖了它。如果你先放置:hover,它就不起作用了。 - Niet the Dark Absol

0

编辑:

抱歉,我误解了问题。

基本上,当您处于活动状态(有鼠标指针)时,您实际上也处于悬停状态。因此,根据CSS规则,它将读取样式表中的最后一个。

当您悬停在链接上并按住鼠标键时,如果我们将伪类视为普通类,则会出现以下情况:

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

所以如果你的 CSS 如下:

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

它将应用红色

但如果你的 CSS 是

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

它将应用绿色

来自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.


你还是没有理解重点。请阅读问题的最后一行! - Joseph Silber
你又错了。我知道当处于:active状态时,同时也处于:hover状态。我在我的问题中已经清楚地说明了这一点。我想要理解的是:为什么这两个伪类具有相同的特异性权重?在我看来,:active应该始终优先于:hover,因为你总是在:active:hover - Joseph Silber
你们似乎都没有理解重点。大家都知道:hover会始终覆盖:link,即使在悬停时它仍然是一个链接。因为每个人都明白,如果你应用了一个样式到:hover状态,那么你就不再关心原始状态。同样的逻辑也应该适用于:active状态... - Joseph Silber

0

这就是它的工作原理,我会尝试解释为什么。我们知道CSS在应用样式时会继续搜索文档,并应用最适用于该元素的样式。

例如:

li.betterList { better list styling here }

更加具体并将覆盖

li { list styling here }

这些伪类选择器的特异性都被视为相同,因此最后一行会覆盖之前的内容。这一点在 W3Schools 的说明中得到了确认。

注意:在 CSS 定义中,如果要生效,则 :active 必须在 :hover(如果有)之后出现!

你也可以把这段 CSS 放在你的 jsfidle 上观察它们被覆盖的情况,因为它们的特异性是相同的。

.works {background: red}
.works {background: green}

0

这是预期的行为,因为大多数人总是将 ":hover" 伪类放在规则组的末尾。

声明顺序对于伪类很重要(请参见此处:http://reference.sitepoint.com/css/pseudoclasses),因此最终规则具有优先权,就像 CSS 中的其他规则一样。

对于大多数人来说,我认为所需的行为:

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

由于:active不是很有用,因此被省略了...或与a:linka:visited结合使用...然后被a:hover覆盖。

W3C在这里详细说明:

请注意,A:hover必须放置在A:link和A:visited规则之后,否则级联规则将隐藏A:hover规则的“color”属性。同样,因为A:active放置在A:hover之后,所以当用户同时激活和悬停在A元素上时,将应用活动颜色(青柠色)。

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

即使是W3schools也对这个问题有正确的理解:
注意:在CSS定义中,a:hover必须放在a:link和a:visited之后才能生效!!
注意:在CSS定义中,a:active必须放在a:hover之后才能生效!!

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


0

我认为您至少应该考虑一下链接或按钮上的用户交互流程。

通常,

  1. :link 一直是默认状态(未触碰)
  2. 当用户指向按钮时,:hover 开始发挥作用。
  3. 一旦用户指向链接或按钮,然后他/她会点击,这时就需要 :active

这就是我们与链接(或按钮)交互的标准顺序。唯一的例外是 :visited,只有当用户之前按过链接时才会有明显的结果。

如果您在处理链接(除了 :visited,它不适用于按钮)时记住助记符“ LVHATE ”将非常有帮助。

但是,如果您真的要进行覆盖,比如想在已访问的链接处于活动状态时更改其颜色,则可以采取以下措施:

a:visited:active {
     color: red;   
}

然而,归根结底,如果没有必要,请避免更改标准的顺序。


0

你可以使用:not()选择器,使:active伪类覆盖:hover伪类,而不管声明的顺序如何。

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

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

这样,只有在没有触发 :active 选择器时才会触发 :hover 选择器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接