焦点指示伪类 :focus-visible
“焦点指示器”顾名思义,通过视觉(通常是某种轮廓)来指示元素获得焦点。这听起来足够简单,完美地描述了旧的 :focus
选择器所能实现的功能。然而,几十年来,浏览器是否会原生显示焦点指示器一直是一个相当复杂的问题。

基于大量的反馈和研究,浏览器长期以来一直采用关于元素类型以及其如何获得焦点的启发式方法,以确定是否应显示焦点指示器。如果用户通过键盘浏览页面,则应该显示。在其他情况下,则取决于具体情况。例如,文本输入框无论如何获得焦点,都会显示指示器。这很重要,因为所有用户都需要知道他们的输入数据将被放置在哪里。不采用这些启发式方法的界面会让人感觉不自然。
旧的 :focus
选择器的目标是允许作者更好地设置焦点指示器的样式,使其与整体设计选择保持一致。问题在于使用它意味着失去了启发式方法。不幸的是,最终结果是 :focus
选择器最常见的用途是完全移除指示器。这避免了导致许多用户抱怨的“假阳性”焦点样式。问题在于移除焦点样式会破坏网站可访问性,给使用键盘浏览页面的人带来麻烦。
幸运的是,一个新的 CSS 选择器应运而生,它避免了这种可访问性问题,同时提供了 Web 开发者所期望的行为。:focus-visible
伪类根据浏览器的启发式方法匹配元素。它允许 Web 作者仅当焦点指示器会原生绘制时才对其进行样式设置。
尽管这是一个最近才在 Web 平台上推出的新功能,但它已被近 1% 的网页使用(根据 HTTP Archive 的 Web Almanac)。
实现
截至 Safari 技术预览版 138,:focus-visible
选择器已添加到 WebKit,并特别关注与其他实现的互操作性。作为 WebKit 实现的一部分,Web 平台测试套件得到了大量改进和扩展,增加了对新用例的覆盖范围,并确保了不同实现之间更好的互操作性。
这项工作带来了全面的变化和改进。经过测试和讨论,所有浏览器现在都遵循一套共同的启发式方法,并在大多数情况下具有相同的行为。例如,在 WebKit 中,默认情况下点击 <div tabindex="0">
将不再显示焦点指示器(与其它浏览器引擎保持一致)。
此外,所有浏览器中的默认用户代理样式表现在都使用 :focus-visible
伪类。这是一个很好的改进,因为它避免了最初使用 :focus
时出现的问题,并且绕过了需要使用一些奇怪的变通方法(例如 :focus:not(:focus-visible)
)来设置浏览器绘制的默认焦点指示器样式。
如果您对实现细节感兴趣,可以阅读在开发过程中撰写的一系列博客文章,网址是 blogs.igalia.com/mrego,或者观看此演讲。
示例
关于 :focus-visible
最近发生的所有变化的好消息是,现在您只需使用 :focus-visible
选择器来设置浏览器引擎绘制的焦点指示器的样式。
最重要的是,当用户不期望时,浏览器不再显示焦点指示器,例如通过鼠标点击聚焦普通元素。
Web 作者将不再需要任何变通方法来实现设置 Web 引擎显示的焦点指示器样式的目标。
例如,如果您希望焦点指示器具有带小偏移的粗洋红色轮廓,则只需在您的网站上使用以下 CSS
:focus-visible {
outline: solid thick magenta;
outline-offset: 0.1em;
}

您可以使用其他属性,而不仅仅是与轮廓相关的属性,来自定义网站中的焦点指示器。例如:
:focus-visible {
outline: dotted thick green;
background: lime;
box-shadow: 0.3em 0.3em lightgrey;
}

公开优先排序
值得一提的是,这项工作是经由 Igalia 的公开优先排序活动,在众多引擎中集体选出,并部分由公众资助。这项努力旨在民主化 Web 平台功能的开发,让个人团体和小型组织有机会直接影响 Web 生态系统。如果您想了解更多信息,Eric Meyer 在 W3C 的 TPAC 上发表了演讲进行解释。
感谢众多贡献,这项实验不仅促成了 WebKit 中 :focus-visible
的开发,还在其他实现中进行了大量的互操作性工作和对齐,并证实了对该功能的实际需求。感谢所有参与者。
反馈
:focus-visible
伪类已在 Safari 技术预览版 138 中默认启用,请试用并报告您在 bugs.webkit.org 上发现的任何问题。您也可以向 @regocas 或 @webkit 发送推文,分享您对此功能的看法。