CSS 教程 / CSS 链接状态与可见的键盘焦点

使用伪类如 :link、:visited、:hover 和 :focus-visible 对链接状态进行样式设置,同时保持链接的可识别性。键盘用户需要可见的焦点指示,而仅靠悬停样式无法传达所有交互状态。

使链接可识别

a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

链接是通过包含 href 的 a 元素创建的。仅将文本着色为蓝色并不能使其成为实际的链接。下划线也能让难以区分颜色的读者知道哪些部分可以点击。text-underline-offset 调整文字与下划线之间的距离。这里 em 是基于链接的字体大小。

使用描述连接的名称,例如“访客信息”,而不是未知目的地,例如“点击”。在将普通链接表现得像按钮之前,你需要区分它是导航还是操作。链接适用于跳转到其他页面或同一页面的目标位置的元素,而按钮通常适用于在当前屏幕上执行操作的元素。

比较链接状态和声明顺序

选择器 适用情况 示例中看到的变化
a:link 尚未访问的链接 蓝色 #1756a9
a:visited 浏览器已将其视为已访问的目标 紫色 #6b438c
a:hover 指针悬停在链接上 红色 #b53239
a:active 激活链接时,例如按下鼠标时 深红色 #8a2630
a:link { color: #1756a9; }

a:visited { color: #6b438c; }

a:hover { color: #b53239; }

a:active { color: #8a2630; }

一个链接可以同时匹配多个状态:指针下的已访问链接同时匹配 :visited 和 :hover。在选择器优先级相同且其他层叠条件相同的情况下,对于相同的属性,后面的声明将优先。link → visited → hover → active 的顺序使得悬停和按下的颜色无论目标是否已访问都可观察到。参见 CSS 组合符与伪类。

此顺序并不优于所有规则。如果你有更具体的选择器或其他层叠条件,结果会不同。如果颜色没有变化,请在开发者工具中检查应用了哪个颜色声明。:active 只表示激活过程中的暂态,不能持续标记当前菜单项。如果你需要显示当前页面菜单,可以考虑使用单独的类或语义化显示,例如 aria-current。

保持键盘焦点可见

a:focus-visible {
  outline: 3px solid #9b5d00;
  outline-offset: 3px;
}

焦点指的是将接收键盘输入的对象。如果在使用 Tab 导航到链接时当前位置不可见,用户就很难知道在哪里按回车键。:focus-visible 适用于浏览器确定显示焦点是必要的情况。它通常出现在键盘移动中,但并非所有点击/输入情况都可以简单地分为两类。同样的焦点原则也适用于表单控件,相关状态可参考 CSS 表单状态:焦点、验证、disabled 与 readonly 。

outline 绘制焦点轮廓,而 outline-offset 将其与元素分开。除非提供了适当的替代品,否则不要使用 outline: none 删除默认指示器。此示例保留了链接下划线和可见的焦点轮廓。请参见 MDN::focus-visible。

创建由两个文件组成的示例

在同一文件夹中创建 links.html 和 visit.html。将第一个代码保存为 links.html,将下一个代码保存为 visit.html,编码为 UTF-8。第一个链接将带您到实际的独立文件,第二个链接将带您到当前页面内的营业时间标题。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Link states exercise</title>
  <style>
    body { margin: 24px; font: 1rem/1.7 sans-serif; color: #333; }
    main { max-width: 65ch; }
    a { text-decoration: underline; text-underline-offset: 0.15em; }
    a:link { color: #1756a9; }
    a:visited { color: #6b438c; }
    a:hover { color: #b53239; }
    a:active { color: #8a2630; }
    a:focus-visible { outline: 3px solid #9b5d00; outline-offset: 3px; }
    nav li + li { margin-block-start: 0.7em; }
  </style>
</head>
<body>
  <main>
    <h1>Small Garden visitor information</h1>
    <nav aria-label="Instruction link"><ul>
      <li><a href="visit.html">Visitor information on a separate page</a></li>
      <li><a href="#hours">Opening hours on this page</a></li>
    </ul></nav>
    <h2 id="hours">Opening hours</h2>
    <p>Plant care takes place in the morning. These times are fictional sample content, not information about a real facility.</p>
    <p>Hover over the links or press Tab to check their colors and outlines.</p>
  </main>
</body>
</html>
<!doctype html>

<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Visitor Information</title></head>

<body><h1>Visitor information page</h1><p>This separate document is opened by the first link.</p><p><a href="links.html">Return to the link exercise</a></p></body></html>

使用鼠标和键盘测试链接

  1. 打开 links.html 并将鼠标悬停在第一个链接上。检查它是否变红。如果按住鼠标按钮,您会看到深红色。由于页面在释放时会移动,因此点击后活动颜色不会保留。
  2. 打开第一个链接,然后使用浏览器的后退功能返回。将指针移出链接并检查访问颜色。在新用户配置文件、隐私窗口或清除历史记录的情况下,结果可能会有所不同,若地址此前已经访问,首次打开练习时也可能直接显示已访问状态。
  3. 将指针放在链接外,然后使用 Tab 键切换到第一个链接。确保出现深棕色轮廓,然后再次按 Tab 键到下一个链接。Shift+Tab 可以按相反顺序移动。
  4. 聚焦第一个链接,按回车。确保 visit.html 打开。当你返回时,使用回车激活第二个链接,它应该带你到营业时间标题。

已访问的显示有隐私限制。一些颜色属性,如 color,可以使用,但大小、图像等不能随意更改以判断是否已访问。为保护隐私,浏览器会让 getComputedStyle() 等接口返回未访问状态的颜色,因此不要仅根据计算的样式值来判断访问历史。详细限制描述见 MDN 中的 :visited 以及隐私声明 。

诊断缺失的状态变化

  • 如果链接无法跳转,检查 href 的文件名和 visit.html 的位置。首先,检查是否将两个文件放在同一文件夹中。
  • 如果只看到悬停颜色,而没有看到访问颜色,将指针移出链接。如果在开发者工具中强制启用了悬停,请将其关闭。
  • 如果键盘无法操作,检查它是否是真正带有 href 的链接。您的浏览器/操作系统的键盘导航设置也可能有影响。
  • 当焦点线被截断时,检查父元素的溢出和周围空间。在移动设备触摸操作中,悬停可能与桌面行为不同,因此必要的信息不仅仅显示在悬停时。

一旦你完成了练习更改规则顺序的操作,就将它们恢复到原来的顺序。未启用工作区保存或本地覆盖时,在开发者工具中临时修改的 CSS 会在刷新后恢复为文件中保存的值,但仅通过刷新并不会重置浏览历史。