样式聚焦

焦点指示标志(通常以“焦点环”表示)可标识页面上当前获得焦点的元素。对于无法使用鼠标的用户,此指示器是鼠标指针的替代项,因此非常重要

如果浏览器的默认焦点指示标志与您的设计冲突,您可以使用 CSS 来调整其样式。切记要时刻为键盘用户着想!

使用 :focus 可始终显示焦点指示标志

每当某个元素获得焦点时,系统都会应用 :focus 伪类,无论使用哪种输入设备(鼠标、键盘、触控笔等)或用于聚焦该元素的方法都是如此。例如,下面的 <div> 具有一个使其可聚焦的 tabindex。此外,它还有一个适用于其 :focus 状态的自定义样式:

div[tabindex="0"]:focus {
  outline: 4px dashed orange;
}

无论您使用鼠标来点击它,还是使用键盘通过 Tab 键来点击它,<div> 看上去都始终相同。

遗憾的是,浏览器可能与其应用焦点的方式不一致。某个元素是否获得焦点可能取决于浏览器和操作系统。

例如,下面的 <button> 也有一个适用于其 :focus 状态的自定义样式。

button:focus {
  outline: 4px dashed orange;
}

如果您在 macOS 上的 Chrome 中使用鼠标点击 <button>,应该会看到其自定义焦点样式。不过,如果您在 macOS 上的 Safari 中点击 <button>,将看不到自定义焦点样式。这是因为在 Safari 中,当您点击该元素时,它不会获得焦点。

由于焦点的行为不一致,因此可能需要在不同的设备上进行一些测试,以确保您的焦点样式适用于用户。

使用 :focus-visible 有选择地显示焦点指示标志

每当某个元素获得焦点,并且浏览器通过启发法确定显示焦点指示标志对用户有益时,就会应用新的 :focus-visible 伪类。特别是,如果最近一次用户互动是通过键盘进行的,并且按键操作不包含 元键、ALT / OPTIONCONTROL 键,则 :focus-visible 将匹配。

下例中的按钮将有选择地显示焦点指示标志。如果您使用鼠标对其进行点击,结果与首次使用键盘通过 Tab 键来点击它所得到的结果不同。

button:focus-visible {
  outline: 4px dashed orange;
}

使用 :focus-within 为聚焦元素的父项设置样式

:focus-within 伪类会在元素本身获得焦点或该元素内的另一个元素获得焦点时应用于该元素。

它可用于突出显示页面的某个区域,以吸引用户注意该区域。例如,以下表单不仅在表单本身被选中时获得焦点,还在选中表单任意单选按钮时获得焦点。

form:focus-within {
  background: #ffecb3;
}

何时显示焦点指示标志

有条理,不妨问问自己:“如果您在使用移动设备时点击此控件,是否希望它显示键盘?”

如果答案是“是”,那么控件应该始终显示对焦指示器,无论用于对焦的输入设备是什么。<input type="text"> 元素就是一个很好的例子。无论输入元素最初如何获得焦点,用户都需要通过键盘向元素发送输入,因此始终显示焦点指示标志很有帮助。

如果答案为“否”,则控件可以选择性地显示对焦指示器。<button> 元素就是一个很好的例子。如果用户使用鼠标或触摸屏点击它,操作完成,可能不需要聚焦指示器。不过,如果用户使用键盘进行导航,显示焦点指示器很有用,以便用户使用 ENTERSPACE 键决定是否要点击该控件。

避免使用 outline: none

坦率地说,浏览器决定何时绘制焦点指示符的方式非常混乱。使用 CSS 更改 <button> 元素的外观或为元素指定 tabindex 会导致浏览器的默认焦点环行为开始执行。

一种非常常见的反模式是使用 CSS 移除焦点指示器,例如:

/* Don't do this!!! */
:focus {
  outline: none;
}

如需解决此问题,一种更好的方法是结合使用 :focus:focus-visible polyfill。下面的第一个代码块演示了 polyfill 的工作原理,其下方的示例应用则举例说明了如何使用 polyfill 更改按钮上的焦点指示器。

/*
  This will hide the focus indicator if the element receives focus via the
  mouse, but it will still show up on keyboard focus.
*/
.js-focus-visible :focus:not(.focus-visible) {
  outline: none;
}

/*
  Optionally: Define a strong focus indicator for keyboard focus.
  If you choose to skip this step, then the browser's default focus
  indicator will be displayed instead.
*/
.js-focus-visible .focus-visible {
  …
}