焦点指示器(通常用“焦点环”表示)用于标识网页上处于焦点状态的元素。对于无法或不想使用鼠标的用户,此指示器非常重要,因为它可替代鼠标指针。
如果浏览器的默认焦点指示器与您的设计相冲突,您可以使用 CSS 重新设置其样式。请务必牢记您的用户。
使用 :focus 始终显示焦点指示器
:focus 伪类会应用于处于焦点状态的元素,无论使用的是哪种输入法或设备(例如鼠标、键盘或触控笔)。
例如,以下 <div> 具有使其可聚焦的 tabindex,并为其 :focus 状态设置了自定义样式:
div[tabindex="0"]:focus {
outline: 4px dashed orange;
}
无论您使用什么设备,<div> 在聚焦时看起来都一样。
遗憾的是,浏览器在应用焦点方面可能不一致。元素是否获得焦点可能取决于浏览器和操作系统。
例如,以下 <button> 为其 :focus 状态设置了自定义 CSS。
button:focus {
outline: 4px dashed orange;
}
如果您在 macOS 上的 Chrome 中使用鼠标点击 <button>,应该会看到其自定义焦点样式。不过,如果您在 macOS 上的 Safari 中点击 <button>,则不会看到自定义焦点样式。这是因为在 Safari 中,当您点击元素时,该元素不会获得焦点。
焦点行为不一致。在不同设备上使用不同输入测试网页,确保焦点样式能让用户接受。
使用 :focus-visible 有选择地显示焦点指示器
当元素获得焦点,并且浏览器(通过启发式方法)确定显示焦点指示器对用户有益时,系统会应用 :focus-visible 伪类。具体来说,如果最近一次用户互动是通过键盘进行的,并且按键操作不包含 meta、ALT、OPTION 或 CONTROL 键,则 :focus-visible 会匹配。
以下示例中的按钮会有选择性地显示焦点指示标志。如果您使用鼠标点击,结果会与您先使用键盘切换到该元素的结果不同。
button:focus-visible {
outline: 4px dashed orange;
}
使用 :focus-within 设置聚焦元素的父元素的样式
当元素本身或其子元素获得焦点时,:focus-within 伪类会应用于该元素。它可用于突出显示网页的某个区域,以吸引用户注意该区域。
例如,当表单本身被选中时,以及当表单的任何单选按钮被选中时,表单都会获得焦点。
form:focus-within {
background: #ffecb3;
}
何时显示焦点指示器
一个很好的问题是问问自己:“如果您在使用移动设备时点击此控件,您是否希望它显示键盘?”
- 如果为“是”:无论输入设备是什么,控件都应始终显示焦点指示器。例如,
<input type="text">元素几乎总是如此。用户需要使用键盘向元素发送输入内容,无论输入元素如何获得焦点。 - 如果为“否”:控件可以选择性地显示焦点指示器。例如,当用户使用鼠标或在触摸屏上点击
<button>时,操作即完成。焦点指示器可能是不必要的。不过,如果用户使用键盘进行导航,最好显示焦点指示器,以便用户决定是否要使用 ENTER 或 SPACE 键激活控件。
避免使用 outline: none
坦白地说,浏览器决定何时绘制焦点指示器的方式非常令人困惑。使用 CSS 更改 <button> 元素的外观或为元素提供 tabindex 会触发浏览器的默认焦点环行为。
有时,开发者会使用 CSS 移除焦点指示器:
/* Don't do this!!! */
:focus {
outline: none;
}
解决此问题的更好方法是结合使用 :focus 和 :focus-visible polyfill。第一个代码块展示了填充区的运作方式,下面的示例应用展示了如何使用填充区来更改按钮上的焦点指示器。
/*
This hides the focus indicator if the element receives focus with a
mouse, but it still shows 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 {
...
}