浏览器屏蔽 :visited 对非颜色属性的渲染是隐私保护机制,仅允许 color、background-color 等极少数颜色类属性;lvha 顺序(:link→:visited→:hover→:active)是防止样式覆盖的硬性要求,不可打乱。

:link 和 :visited 只能靠颜色类属性做有限区分,所谓“爱恨原则”(LVHA)不是风格偏好,而是防止样式被静默覆盖的硬性顺序要求。
为什么 a:visited { background: #f0f0f0 } 完全没反应
这不是你写错了,是浏览器主动屏蔽了 :visited 对非颜色属性的渲染——这是隐私保护机制,不是兼容性问题。你写的 background、transform、text-shadow、font-weight、transition 全部被静默丢弃,连 getComputedStyle(el, ':visited') 都返回空或默认值。
允许设置的属性极窄,仅限这些可继承的颜色值:
colorbackground-color-
border-color(包括border-top-color等细分项) outline-colorcolumn-rule-color
注意:background-image 无效;currentColor 在 :visited 中也不可靠,部分浏览器会降级为 color 值本身。
LVHA 顺序不是建议,是避免样式错乱的必要条件
a:link → a:visited → a:hover → a:active 这个顺序一旦打乱,就会出视觉 bug:
- 如果
a:visited写在a:link前面,且两者都设了color,那么所有链接(无论是否访问过)都会按后声明的a:link规则渲染 - 如果
a:hover写在a:visited后面,而两者color不同,鼠标移上去时颜色会切换,但移开后立刻回退到:visited色——因为:hover的权重没赢过后续的:visited - 别用
!important强行覆盖顺序,它会让状态逻辑更难调试,且无法绕过浏览器对:visited的属性限制
href 值无效时 :link/:visited 根本不触发
这两个伪类只对真实 URL 生效。以下写法均不会匹配:
<a href=""></a><a href="#"></a><a href="javascript:void(0)"></a><a href="mailto:test@example.com"></a>
测试时务必用真实路径,比如:
<a href="/article/123"></a><a href="https://example.com"></a>
单页应用中若用前端路由(如 href="/user/profile"),只要浏览器历史中有该条目,:visited 就会生效;但 pushState 不触发更新,:visited 状态不会自动同步。
想加背景、动画或自定义状态?别硬刚 :visited
真要突破限制,唯一可靠路径是放弃依赖浏览器历史,改用 class 手动管理状态:
- 监听
click事件,对event.target.closest('a[href]')添加class="visited" - CSS 写
a.visited { background: #f5f5f5; color: #666; },完全不受浏览器限制 - 配合
localStorage持久化标记,刷新后仍保留状态
这个方案性能无负担,但容易被忽略的关键点是:它和浏览器原生 :visited 并不等价——前者是你自己定义的“已点击”,后者是浏览器记录的“已访问”。如果用户在其他标签页或设备上访问过该链接,class 方案不会感知,必须自行设计跨端同步逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











