在我的样式表中,使用a而不是a:link或a:visited有什么原因吗?

15
有人能告诉我在样式表中使用 a {} 是否有任何理由,而不是使用 a:link, a:visited {} 或者两者并用吗?我测试过在不同的浏览器和网站中得到了不一致的结果,所以我从未找到令人满意的答案。我在谷歌上也没有找到答案。
当然,这是假设在 <a> 标签中永远不会使用 href 属性。也许这是一个错误的假设。
**编辑**
我知道这些选择器的作用。我想知道为什么我应该使用 a 而不是 a:linka:visited,因为 a 总是有一个 href 属性。但正如 Chris Blake 和 Ryan P 在答案中所说,还有 <a name="top"> 和 JavaScript 用法,它们都不需要 href 属性。

1
相关:“a” 和 “a:link”的区别(Jukka K. Korpela提供了一些很好的见解,我在我的答案中进一步阐述,我刚刚发布了这个答案)。 - BoltClock
5个回答

22
当然,这是基于永远不会有使用没有href值的标签的理解。也许这是一个错误的假设。

这取决于你的项目。严格来说,那是一个错误的假设,因为并非每个 <a> 元素都需要有 href 属性。实际上,在 HTML5 中仍然不需要为每个 <a> 指定 hrefChris BlakeRyan P 提到了命名锚点,我要补充的是,虽然在 HTML5 中 <a>name 属性已经作废, 但是由于传统和历史原因,命名锚点依然广泛存在并将继续存在。

话虽如此,从现在开始,建议作者使用 id 属性而不是命名锚点来指定文档锚点片段。

此外,缺少 href 属性但具有用于 JavaScript 的 onclick 属性的 <a> 元素会很混乱。即使您坚持使用 onclick 来绑定事件,在考虑优雅降级的情况下,您也应该至少使用 href 将其指向 某个地方

但为了简化事情,让我们假设您不会编写没有 href 属性的 <a> 元素。

考虑到 CSS 选择器,有两个重要的要点:

它们是否相同?

不,选择器 aa:link,a:visited 不严格等效。我将引用我之前在previous answer上对此问题的回答:

选择器 a 应匹配任何 <a> 元素,而 a:link 仅匹配未访问的超链接 <a> 元素(HTML 4 文档类型将超链接定义为具有 href 属性的 <a> 元素)。在任一规范中都没有说明 a 应自动转换为 a:link 或反之亦然。
换句话说,在HTML中,a:link,a:visited(在CSS1中)严格等同于使用属性选择器的a[href](在CSS2中)或a:any-link(在选择器级别4中引入的新选择器),而不是a。请注意,无论属性是否有值,只要存在伪类就会匹配,因此使用[href]。还要注意,这适用于所有当前的HTML标准,我相信这包括HTML5,因为如上所述,href在任何现有规范中都不是必需属性。
请记住,其他语言可能为:link:visited定义完全不同的语义-它们恰好与HTML中同样具体的选择器重合,下面将介绍这些选择器...

特异性

这是一个很大的坑点:aa:link 或者 a:visited 不够具体,这是特别明显的优先级问题的常见来源,尤其是在分别应用样式到 aa:linka:visited 时。这将导致各种 !important 的hack,以解决对优先级不理解的问题。
例如,考虑以下 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;
}

这并不像预期的那样工作,因为所谓的一般规则/选择器a:linka:visited比所谓的专用规则/选择器body > header > a更加具体,因此标题链接实际上永远不会变成白色。
/* 1 pseudo-class, 1 type  -> specificity = (0,1,1) */
a:link, a:visited

/* 3 types                 -> specificity = (0,0,3) */
body > header > a

现在,大多数CSS编码者首先想到的是加入!important,完全取代特定性:
body > header > a {
    color: white !important;
}

但这会给你带来各种不好的声誉,对吧?所以我们不要那样做。

选择器级别4为您提供了不止一个,而是两个解决此特定性问题的方法。尽管这些新的解决方案在Internet Explorer和Microsoft Edge Legacy(UWP / EdgeHTML /非Chromium版本)中不受支持,但幸运的是有第三种解决方案适用于Internet Explorer 7及更高版本,即a [href],我上面提到的属性选择器。

1. :any-link伪类

:any-link背后有一些历史,您可以在这个问题中阅读我的答案,但实际上,:any-link作为:link,:visited的通配符。它的主要目的是消除选择器重复,并且出现了等效形式:is(:link, :visited)

你可以在专门的规则中使用 a:any-link 来匹配广义的 a:linka:visited 规则的特殊性,从而使其能够覆盖它们:
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. :where() 伪类

:where() 也有一些历史背景,但本质上它是 :is() 的类比,唯一的例外是它会将其参数的特异性归零。请参阅 这个问题 中我的答案,了解它的详细使用方法。

您可以在 :where() 中包装 :link:visited 伪类,以消除它们的伪类特异性,从而允许它们被专门的规则覆盖:

/* 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](适用于旧版浏览器)

幸运的是,如果您需要支持旧版浏览器,属性选择器和伪类一样具有特定性。这意味着您可以使用a[href]来表示a:link和/或a:visited,而不会遇到特异性问题,因为它们具有相同的特定性!

/* 1 attribute, 3 types    -> specificity = (0,1,3) */
body > header > a[href] {
    color: white;
}

那么要使用哪些选择器呢?

这仍然非常主观,但我遵循以下个人经验法则:

  • 对于不依赖于链接状态的样式(即只要是链接就行),请应用到a

  • 对于需要区分链接是否已访问的样式,请应用到a:linka:visited

  • 考虑到上述的特异性问题,请不要在aa:link/a:visited规则之间混合任何声明。如果我需要在某个地方同时应用相同的属性,但我已经有了单独的a:linka:visited规则,则我会使用上述3种选项之一来避免特异性问题。

例如,这是我在网站“即将推出”页面中使用的链接样式:

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);
}

“text-shadow”转换适用于所有“a”元素,无论其是否被访问,因为转换仅在鼠标悬停和单击其中一个元素时才会生效(对应于“a:hover,a:active”规则)。
现在,我希望已访问的链接比未访问的链接稍微深一些,因此我将颜色放在单独的“a:link”和“a:visited”规则中。但是,由于某种原因,我希望页脚链接无论是否被访问都显示相同的颜色。
如果我使用“footer a”,我将遇到上面描述的特异性问题,因此我选择使用“footer a:link,footer a:visited”。这是出于传统原因(正如您将在下面看到的,我最初发布了这个问题是在2012年!),但当然可以缩短为“footer a:any-link”。但是,特异性匹配原则仍然适用。
希望我的建议能帮助您处理链接样式的混乱情况。

1
所以有两个问题。a) 如果我没有为 a:link 设置样式,那么说我不能为 a:hover 设置样式是否已经过时或错误?b) a[href] 在任何现代浏览器(ffx、webkit、IE>7等)中都可以工作吗? - JakeParis
a) 如果使用伪类,您只需确保在 a:linka:visited 后面放置 a:hover,以避免特异性问题(参见此答案)。 b) 所有浏览器都支持它,包括 IE7+。 - BoltClock

3

a:linka:visited有特定的含义。a本身会影响所有<a>元素,而a:link仅影响尚未访问过的链接,a:visited仅影响已访问过的链接。


3
有两种情况下,a 可能没有 href 属性。第一种是普通的锚点(即 <a name="someplace" />),第二种是纯 JavaScript 交互(即 <a onclick="doSomething( );" />)。它们不是“链接”,不应该被以同样的方式进行样式设置。
编辑:为了澄清,a:linka[href] 几乎是等价的(我相信前者的表示法在属性选择器可用或标准化之前就存在了)。因此,使用 a 而不是 a:link 的原因是如果您想要所有锚点标签都使用相同的样式。某些浏览器中的默认样式会显示两个不同的效果,例如下划线仅应用于 a:link 而不是 a

a[href] 的严格等价实际上是 a:link, a:visited。一个表示未访问的链接,另一个表示已访问的链接。确实,一些浏览器(如旧版本的IE)在应用样式到 a 元素时存在不一致性,这取决于是否使用伪类。 - BoltClock
同时,:link:visited是CSS1的一部分(最初的伪类),而属性选择器则是在CSS2中引入的。 - BoltClock

3

a:linka:visited用于指定普通链接和已访问链接的自定义颜色,而a {}用于覆盖所有样式,包括a:linka:visiteda:active。例如,以下链接无论是否处于活动状态、已访问或悬停都具有相同的颜色:

a { color:red; }

你可以通过使用个别样式,例如a:pseudoClass符号来避免这种情况。

请注意,a本身不会覆盖伪类。相反,只有在您指定它们后,伪类才会覆盖它。 - BoltClock

3

你可以拥有一个仅仅是锚点的锚点。例如,

<a href="#top">Return to top</a>

<a name="top">Top</a>

这可以纠正你的错误假设(尽管,“top”不需要锚点,但从哲学上讲,这是最正确的)。

此外,正如Sarfraz所说,a {}会覆盖所有其他a:样式属性的出现,如果有样式的话(并且假设a {}在其他a:声明之后)。


不相关的问题:即使没有明确声明,#top 也存在吗?我从来不知道! - JakeParis
1
@JakeParis 在 <a name="top"> 中声明了 #top。哈希跳转到具有给定 id 的块的行为是较新的行为。 - kitti
没错。在 HTML4 之前,按名称跳转是哈希跳转的官方方法(也许现在已经有点老派了?)。 - chrisdotcode

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