样式焦点

焦点指示器(通常用“焦点环”表示)用于标识页面上当前具有焦点的元素。对于无法使用鼠标的用户来说,此指示器极其重要,因为它充当鼠标指针的替代物。

如果浏览器的默认焦点指示器与您的设计冲突,您可以使用 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 伪类在元素获得焦点且浏览器通过启发式方法确定显示焦点指示器对用户有益时应用。特别是,如果最近的用户交互是通过键盘进行的,并且按键不包括 meta、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 {
  
}