skip to content

CSS3
伪类 :focus-visible 的应用

伪类 :focus-visible 平常很难引起注意,因为如今大多数细节操作都由组件库处理。然而,当你需要自己编写按钮组件时,这个伪类对于提升用户体验非常重要。

曾经的 :focus-visible

在文章 CSS :focus-visible 伪类让我感动哭了 中提到,在 Chrome 浏览器下,一些元素在使用鼠标点击时可能会出现意料之外的焦点轮廓。但是我们不能简单地使用 outline: none; 来处理这个问题,因为我们还需要考虑键盘导航对焦点的触发。

然后,:focus-visible 伪类出现了,它恰好解决了这个问题,因为它只对键盘导航触发的焦点有效。

以下 CSS 代码的作用是在不影响键盘导航触发焦点轮廓的情况下,去除鼠标点击触发的焦点轮廓:

:focus:not(:focus-visible) {
  outline: 0;
}

现在的 :focus-visible

距离文章发表日期已经过去近 4 年的时间,现在在使用 Chrome 浏览器点击文中提到的元素时,不会再出现意料之外的焦点轮廓。因此,对这些元素使用 :focus:not(:focus-visible) 已经不再必要。

然而,如果你只想为鼠标点击状态下的按钮编写样式,使用 :focus:not(:focus-visible) 仍然非常有必要。因为如果只使用 :focus,样式也会应用于通过键盘导航触发的焦点。

当然,有些人采取激进的方式,只使用 :focus-visible 而不使用 :focusCSS focus-visible is my new default

Antd Button

在查看 Antd Button 的样式代码 时,我发现了两个有趣的点:

  1. button 的样式中并没有使用 :focus 伪类。这可能是出于对按钮在点击后能够恢复到未点击状态的考虑。当然,这也取决于组件的设计语言,因为有些按钮在设计时并不需要在点击后恢复到未点击状态。
  2. :focus-visible 伪类出现在 genFocusStyle 函数中

尽管没有使用 :focus,但并不意味着没有处理点击状态。在 Antd 中,使用 JavaScript 动态插入和移除一个 <div/> 来模拟点击状态(源码)。

有了 JavaScript 处理鼠标点击状态,使用 :focus-visible 就更加纯粹,只需要关注键盘导航触发的焦点即可。

genFocusStyle 函数中生成了与 :focus-visible 相关的代码(genFocusStyle 被调用位置genFocusStyle 函数)​

通过这种方式,Antd 可以更好地处理按钮组件的焦点状态,提升用户体验。