问题描述
谁能告诉我是否有任何理由在我的样式表中使用 a {}
而不是(或与之相邻的)a:link, a:visited {}
?我在浏览器、网站等方面对此进行了不一致的测试,所以我从来没有给出令人满意的答案.我也无法在 Google 上找到答案.
这当然是假设 从不 有理由使用没有 href
值的 <a>
标记.也许这是一个错误的假设.
** 编辑 **
我知道这些选择器做什么.我正在寻找使用 a
而不是 a:link
或 a:visited
的原因,因为 a
总是有一个 href
属性.但正如 Chris Blake 和 Ryan P 在答案中所说,还有 <a name="top">
和 javascript 用法,两者都不需要 href
属性.
这当然是假设 从不 有理由使用没有 href
值的 <a>
标记.也许这是一个错误的假设.
这取决于您的项目.严格来说,is 是一个错误的假设,因为并非每个 <a>
元素都需要具有 href
属性.事实上,在 HTML5 中仍然没有要求为每个 <a>
指定 href
.Chris Blake 和 Ryan P 提到了命名锚点,我将在 <a>
的 name
属性中添加这一点已自 HTML5 起已过时,仅凭传统和传统,命名主播仍然很普遍,并将继续存在.
也就是说,今后,建议作者使用 id
属性而不是命名锚来指定文档锚片段.
此外,缺少 href
属性但具有 JavaScript 的 onclick
属性的 <a>
元素是一团糟.即使您坚持使用 onclick
来绑定事件,为了优雅降级,您至少应该使用 href
将其指向某处.
但为了简单起见,我们假设您不会编写没有 href
属性的 <a>
元素.
考虑到这一点,回到 CSS 选择器,有两点需要考虑:
它们是一样的吗?
不,选择器 a
和 a:link, a:visited
不是严格等价的.我将引用我关于此主题的以前的答案:
选择器 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,接下来会介绍...
特异性
这是一个很大的问题:a
不如 a:link
或 a:visited
那样具体,后者是一个非常常见的来源将样式分别应用于 a
、a:link
和 a:visited
时特别明显的特殊性问题.这会导致各种 !important
黑客攻击来解决对特异性缺乏理解的问题.
例如,考虑这个 CSS:
/* 所有未访问的链接都应该是红色的 */一条链接 {红色;}/* 所有访问过的链接应该稍微暗一些 */一个:访问{颜色:栗色;}/* 但无论如何,标题链接必须始终是白色的!*/身体>标题>一个 {白颜色;}
这不能按预期工作,因为 a:link
和 a:visited
(我称之为通用规则/选择器)比 body 更具体>标题>a
(我称之为专用规则/选择器),因此标题链接实际上永远不会是白色的:
/* 1 个伪类,1 个类型 ->特异性 = (0,1,1) */一个:链接,一个:访问过/* 3 种类型 ->特异性 = (0,0,3) */身体>标题>一个
现在大多数 CSS 编码人员首先想到的就是加入 !important
,完全胜过具体性:
body >标题>一个 {颜色:白色!重要;}
但这会让你得到各种各样的坏名声,对吧?所以我们不要那样做.
选择器级别 4 为您提供的不是一个,而是 两个 解决此特异性问题的解决方案.这些解决方案虽然是新的,但在 Internet Explorer 和 Microsoft Edge Legacy(UWP/EdgeHTML/not-Chromium 之一)中不受支持,但幸运的是,还有第三种解决方案适用于 Internet Explorer 7 及更高版本,即 a[href]
,我上面提到的属性选择器.
1.:any-link
伪类
:any-link
背后有一些历史,您可以在我对 this question,但实际上,:any-link
可以作为 :link, :visited 的包罗万象代码>.它的主要目的是消除选择器重复,因此实际上存在
:is(:link, :visited)
形式的等价物.
您可以在您的专门规则中使用 a:any-link
来匹配广义 a:link
和 a:visited
的特异性规则,从而允许它覆盖它们:
a:link {红色;}一个:访问{颜色:栗色;}/* 1 个伪类,3 种类型 ->特异性 = (0,1,3) */身体>标题>一个:任何链接{白颜色;}
2.:where()
伪类
:where()
背后也有一些历史,但本质上它是 :is()
的类似物,不同之处在于它将其参数的特异性归零.请参阅我对这个问题的回答深入了解其工作原理.
您可以将 :link
和 :visited
伪类包装在 :where()
中,以消除它们的伪类特异性,从而允许它们被专门规则覆盖:
/* 1 type ->特异性 = (0,0,1) */一个:哪里(:链接){红色;}/* 1 种类型 ->特异性 = (0,0,1) */一个:哪里(:访问){颜色:栗色;}/* 3 种类型 ->特异性 = (0,0,3) */身体>标题>一个 {白颜色;}
3.a[href]
(适用于旧版浏览器)
幸运的是,如果您需要支持旧版浏览器,属性选择器与伪类一样具体.这意味着您可以使用 a[href]
来表示 a:link
和/或 a:visited
,而不会遇到具体情况问题,因为它们同样具体!
/* 1 个属性,3 种类型 ->特异性 = (0,1,3) */身体>标题>一个[href] {白颜色;}
那么使用哪个选择器?
这仍然非常主观,但我遵循以下个人经验法则:
应用于 不依赖于链接状态的
a
样式(即只要是链接就可以).应用到
a:link
和a:visited
样式,其中确实很重要链接是否被访问.考虑到上面提到的特殊性问题,both
a
和a:link
/a:visited 规则.如果我需要将相同的属性应用于某处的两个状态,但我已经在单独的a:link
和a:visited
规则中拥有它,我将使用其中一个以上 3 个选项可避免特异性问题.
例如,以下是我在网站发布前的即将推出"页面中使用的链接样式:
a {文字装饰:无;过渡:文本阴影 0.15s 线性;}一条链接 {颜色:RGB(119、255、221);}一个:访问{颜色:RGB(68、204、170);}一个:悬停,一个:活动{文字阴影:0 0 0.5em 当前颜色;}一:焦点{轮廓:细点;}/* ... */页脚a:链接,页脚a:访问{颜色: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
.但是,特异性匹配原则同样适用.
希望我的建议可以帮助您处理链接样式的混乱.
Can anyone tell me if there's any reason to use a {}
instead of (or adjacent to) a:link, a:visited {}
in my stylesheet? I've had inconsistent results testing this across browsers, sites, etc, so I've never come up with a satisfactory answer. I was not able to find an answer on The Google, either.
This is of course assuming there would never be a reason to use an <a>
tag without an href
value. Maybe that's a mistaken assumption.
** EDIT **
I know what these selectors do. I'm looking for reasons why I would use a
instead of a:link
or a:visited
, since a
always has an href
attribute. But as Chris Blake and Ryan P said in the answers, there is also <a name="top">
and javascript usage, neither of which would need the href
attribute.
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:
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.
这篇关于是否有理由在我的样式表中使用 a 而不是 a:link 或 a:visited?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!