:focus-visible

Baseline 已广泛支持

此特性已经十分成熟,可在许多设备和浏览器版本上使用。自 2022 年 3 月起,它已在各浏览器中可用。

:focus-visible 伪类在元素匹配 :focus 伪类,并且用户代理(User Agent)通过启发式方法确定焦点应该在元素上显现时应用。(在这种情况下,许多浏览器默认会显示一个“焦点环”。)

试一试

label {
  display: block;
  margin-top: 1em;
}

input:focus-visible {
  outline: 2px solid crimson;
  border-radius: 3px;
}

select:focus-visible {
  border: 2px dashed crimson;
  border-radius: 3px;
  outline: none;
}
<form>
  <p>Which flavor would you like to order?</p>
  <label>Full Name: <input name="firstName" type="text" /></label>
  <label
    >Flavor:
    <select name="flavor">
      <option>Cherry</option>
      <option>Green Tea</option>
      <option>Moose Tracks</option>
      <option>Mint Chip</option>
    </select>
  </label>
</form>

此选择器可用于根据用户的输入模式(鼠标与键盘)提供不同的焦点指示器。

语法

css
:focus-visible {
  /* ... */
}

:focus 与 :focus-visible

最初,用户代理 CSS 仅根据 :focus 伪类设置焦点样式,为大多数获得焦点的元素设置焦点环轮廓。这意味着所有元素,包括所有链接和按钮,在获得焦点时都会应用焦点环,许多人认为这很难看。由于外观问题,一些作者移除了用户代理的轮廓焦点样式。更改焦点样式会降低可用性,而移除焦点样式则会使有视觉障碍的用户无法进行键盘导航。

浏览器不再在每个获得焦点的元素周围可见地指示焦点(例如,通过绘制“焦点环”)。相反,它们使用各种启发式方法仅在对用户最有帮助时才提供焦点指示器。例如,当使用指向设备点击按钮时,通常不会视觉指示焦点,但当需要用户输入的文本框获得焦点时,会指示焦点。虽然当用户使用键盘导航页面或通过脚本管理焦点时始终需要焦点样式,但当用户知道焦点在哪里时(例如,当他们使用鼠标或手指等指向设备实际将焦点设置在元素上时),则不需要焦点样式,除非该元素仍需要用户关注。

:focus 伪类始终匹配当前获得焦点的元素。:focus-visible 伪类也匹配获得焦点的元素,但仅当用户需要被告知焦点当前在哪里时。由于 :focus-visible 伪类在需要时匹配获得焦点的元素,因此使用 :focus-visible(而不是 :focus 伪类)允许作者在不改变焦点指示器出现时间的情况下更改焦点指示器的外观。

当使用 :focus 伪类时,它总是针对当前获得焦点的元素。这意味着当用户使用指向设备时,一个可见的焦点环会出现在获得焦点的元素周围,一些人认为这很碍眼。:focus-visible 伪类尊重用户代理的选择性焦点指示行为,同时仍然允许焦点指示器自定义。

无障碍

低视力

确保有低视力的人能够看到视觉焦点指示器。这也将有利于在光线充足的空间(如阳光下)使用屏幕的任何人。WCAG 2.1 SC 1.4.11 非文本对比度要求视觉焦点指示器至少为 3 比 1。

认知

如果一个人使用混合输入形式,焦点指示器出现和消失的原因可能不明显。对于有认知问题或技术知识较少的用户来说,这种交互元素缺乏一致的行为可能会令人困惑。

示例

比较 :focus 和 :focus-visible

此示例展示了三对控件。每对都包含一个 text 输入和一个按钮。

  • 第一对不为焦点状态添加任何自定义样式,并显示默认情况。
  • 第二对使用 :focus 伪类添加样式。
  • 第三对使用 :focus-visible 伪类添加样式。
html
<input type="text" value="Default styles" /><br />
<button>Default styles</button><br />

<input class="focus-only" type="text" value=":focus" /><br />
<button class="focus-only">:focus</button><br />

<input class="focus-visible-only" type="text" value=":focus-visible" /><br />
<button class="focus-visible-only">:focus-visible</button>
css
input,
button {
  margin: 10px;
}

.focus-only:focus {
  outline: 2px solid black;
}

.focus-visible-only:focus-visible {
  outline: 4px dashed darkorange;
}

如果你依次点击每个元素,你会看到当使用 :focus 来设置焦点环样式时,用户点击按钮时用户代理会绘制焦点环。然而,当使用 :focus-visible 来设置焦点环样式时,用户点击按钮时用户代理不会绘制焦点环,就像在默认情况下一样。

如果你接着通过 Tab 键遍历每个元素,你会看到在所有三种情况下——默认、:focus:focus-visible——当用户使用键盘导航到按钮时,用户代理都会在按钮周围绘制焦点环。

这表明 :focus-visible 如何使设计者能够遵循浏览器逻辑来确定何时应该显示焦点环。

提供 :focus 回退

如果你的代码必须在不支持 :focus-visible 的旧浏览器版本中工作,请使用 @supports 检查 :focus-visible 的支持情况,并在其中重复相同的焦点样式,但放在 :focus 规则内。请注意,即使你根本没有为 :focus 指定任何内容,旧浏览器也会简单地显示原生轮廓,这可能就足够了。

html
<button class="button with-fallback" type="button">Button with fallback</button>
<button class="button without-fallback" type="button">
  Button without fallback
</button>
css
.button {
  margin: 10px;
  border: 2px solid darkgray;
  border-radius: 4px;
}

.button:focus-visible {
  /* Draw the focus when :focus-visible is supported */
  outline: 3px solid deepskyblue;
  outline-offset: 3px;
}

@supports not selector(:focus-visible) {
  .button.with-fallback:focus {
    /* Fallback for browsers without :focus-visible support */
    outline: 3px solid deepskyblue;
    outline-offset: 3px;
  }
}

规范

规范
选择器 Level 4
# the-focus-visible-pseudo

浏览器兼容性

另见