:link和:visited仅作用于带非空href的元素,分别匹配未访问和已访问链接;:visited受严格样式限制(仅允许color等少数属性),且必须按LVHA顺序声明,否则:hover/:active失效。

:link 和 :visited 不是用来“重构锚点默认状态”的,它们只作用于带 href 属性的 <a> 元素,且仅区分访问历史;没有 href 的锚点(如 <a id="section1"></a>)完全不匹配这两个伪类。
为什么 :link 对纯锚点(无 href)无效
浏览器判定 :link 的前提是:元素是 <a> 标签 且 具有非空 href 属性并指向有效 URL。常见误用场景:
- 写成
<a id="top">回到顶部</a>—— 没href,:link和:visited都不触发 - 写成
<a href="#section1">跳转</a>—— 这是合法链接,:link生效;但目标锚点<a id="section1"></a>本身仍不匹配任何链接伪类 - 用 JS 动态插入
href后再期望样式自动生效 —— 伪类匹配发生在 DOM 解析时,动态补href不会触发重匹配(需手动 toggle class)
:visited 的样式限制远比你想象中严格
现代浏览器(Chrome 136+、Firefox、Safari)对 :visited 可设置的属性做了硬性裁剪,不是“不推荐”,而是直接忽略:
- 只允许:
color、background-color、border-color、outline-color、text-decoration-color - 禁止:
display、visibility、font-size、transform、transition、margin、padding、width、height、background-image - 哪怕写了
transition: color 0.2s,整个a:visited规则都可能被丢弃(部分浏览器行为) -
rgba()中的 alpha 值会被四舍五入为 0 或 1,无法实现半透明效果
LVHA 顺序不是建议,是 CSS 解析的硬性依赖
如果你只写 a:link 和 a:visited,却漏掉 :hover 和 :active,或打乱顺序,结果不是“少两个效果”,而是已访问链接的悬停/点击反馈彻底失效:
立即学习“前端免费学习笔记(深入)”;
- 错误写法:
a:hover { color: red; } a:visited { color: gray; }→ 所有已访问链接将永远卡在gray,:hover完全不生效 - 正确写法必须是:
a:link→a:visited→a:hover→a:active(缺一不可) - 哪怕你只想改颜色,也要写全四句,否则层叠引擎会把后续状态“压死”
- 局部选择器如
.nav a:link权重高于全局a:link,但内部仍须遵守 LVHA
替代方案:当真需要控制锚点视觉状态时
纯锚点(id)无法用 :link/:visited 控制,但你可以用更可控的方式模拟:
- 给跳转链接加
href="#section1",再用 JS 监听hashchange,根据当前location.hash给对应目标区域加.is-active类 - 用
:target伪类匹配当前 URL 片段指向的元素(如#section1对应<div id="section1"></div>),但它和:visited无关,也不记录历史 - 若要持久化“用户是否看过某区块”,必须用 localStorage + class 切换,CSS 伪类做不到
真正容易被忽略的是::visited 不是“已读标记”,它是浏览器基于本地历史数据库的粗粒度匹配,且受跨域隔离、隐私分区(Chrome 136+ “已访问链接分区”)影响,同一链接在不同上下文里可能被识别为不同状态。


















