每个前端开发人员都会遇到这种情况:你的老板、客户或设计师认为浏览器在聚焦元素上应用的轮廓与 UI 不匹配,并要求你将其删除。或者你甚至可能想自己删除它。
所以你做了一些研究,发现 强烈建议不要这样做,因为焦点轮廓的存在是有原因的:它为键盘导航(使用 Tab 键)提供视觉反馈,让无法使用鼠标或有视力障碍的用户知道他们在屏幕上的位置。

但这并不意味着你只能忍受这个轮廓。与其删除它,不如用其他东西替换它。这样,你就可以保持界面的可访问性,并且可以更灵活地控制它的外观,以便更好地匹配你的 UI。
你可以先通过选择元素的聚焦状态并应用 outline: none
来删除默认的浏览器轮廓。然后,你可以从以下选项中选择其中一个来替换它
更改背景颜色
这最适合可以填充的元素,例如按钮。选择元素的聚焦状态并为其应用对比色背景。对比度越高越好,因为细微的改变可能不足以成为强烈的视觉提示,尤其是在色盲和低视力情况下。
在下面的示例中,背景和边框颜色都会改变;你可以选择其中一个或两个。
单击或使用 Tab 键聚焦以查看此状态的外观。
查看 CodePen 上的
使用背景颜色替换原生轮廓焦点的元素,作者 Lari (@larimaza)
在 CodePen 上。
更改文本颜色
如果元素包含任何文本,你可以选择聚焦状态并更改其颜色。这对于使用 mask-image
应用的图标也有效;你可以选择作为聚焦元素后代的图标并更改其背景颜色,就像下面的示例按钮。
查看 CodePen 上的
使用文本和图标颜色替换原生轮廓焦点的元素,作者 Lari (@larimaza)
在 CodePen 上。
同样,对比度是关键。你也可以考虑在文本链接上使用下划线,并将其作为更改状态的一部分,因为,正如 网页内容无障碍指南 指出
颜色不用作传达信息、指示操作、提示响应或区分视觉元素的唯一视觉手段。(A 级)
了解成功标准 1.4.1
应用阴影
box-shadow
属性可以完全像轮廓一样工作,只是它更强大——你现在可以控制它的颜色、不透明度、偏移量、模糊半径和扩散半径。如果指定了 border-radius
,则阴影会遵循相同的圆角。
查看 CodePen 上的
使用阴影替换原生轮廓焦点的元素,作者 Lari (@larimaza)
在 CodePen 上。
你可以用这种技术变得非常有创意(不过认真地说,不要这样做)
查看 CodePen 上的
使用疯狂的阴影替换原生轮廓焦点的元素,作者 Lari (@larimaza)
在 CodePen 上。
这适用于几乎所有类型的可聚焦元素,例如切换、复选框、单选按钮和滑块。
查看 CodePen 上的
使用阴影替换原生轮廓焦点的切换和单选按钮,作者 Lari (@larimaza)
在 CodePen 上。
增大元素的大小
作为颜色改变的替代方案,你也可以使用微妙的大小修改作为焦点反馈。在此示例中,我们使用 transform: scale
。
查看 CodePen 上的
使用 transform scale 替换原生轮廓焦点的元素,作者 Lari (@larimaza)
在 CodePen 上。
这里的关键是微妙。极端的尺寸变化可能会导致内容重排,更不用说对 那些希望减少运动的人 来说体验很差。
复制现有的悬停样式
如果元素已经具有对比色悬停样式,你可以简单地将该样式也应用于聚焦状态。这是一个相当优雅的解决方案,因为你不需要在界面中添加任何新的颜色或轮廓。
以下是一个示例,其中焦点和悬停状态都采用了与元素默认样式的背景形成高度对比的颜色
查看 CodePen 上的
使用悬停样式替换原生轮廓焦点的元素,作者 Lari (@larimaza)
在 CodePen 上。
奖励:自定义默认轮廓
到目前为止,我们所讨论的所有内容都假设我们要完全删除焦点轮廓。我们不必这样做!事实上,它是一个我们可以自定义的边框。
button:focus {
outline: 3px dashed orange;
}
那是简写,如果我们想微调样式,可以这样写
button:focus {
outline-width: 3px;
outline-style: dashed;
outline-color: orange;
}
我们拥有的另一个超能力是 outline-offset
属性,它与 outline
简写属性分开,但可以与它一起使用以更改焦点环的位置
button:focus {
outline: 3px dashed orange;
outline-offset: 10px;
}
结论
你可以将所有这些选项混合搭配,以获得适合界面中每个组件类型的自定义样式。
并且值得重复:在采用自定义焦点状态时,不要忘记使用鲜明的颜色对比度和其他视觉提示来代替颜色。当然,我们都希望获得与我们的设计相一致的体验,但我们可以在此过程中坚持良好的可访问性实践。W3C 建议使用此工具 来测试颜色值相对于 WCAG 指南的对比度。
人们倾向于删除焦点样式的主要原因不是键盘焦点,而是鼠标焦点——也就是说,单击的元素保留其焦点状态的方式,使按钮在使用后保留轮廓或其他效果。对于这种情况,我建议在事件处理函数中添加
e.target.blur()
,这将在单击按钮后取消按钮的焦点。或者,为了获得更好的解决方案,我喜欢这样做
这样做会检查事件的 X 坐标是否为 0,然后再取消焦点。除非鼠标在用户单击时位于屏幕的最左侧(这实际上不应该发生,因为有填充等),否则坐标将大于 0。另一方面,键盘事件始终返回 0。所以这将对鼠标事件取消焦点,但对键盘事件不会,允许使用键盘或其他设备进行导航的用户保留其导航位置。
当你使用上面的代码时,点击输入框会发生什么?
希望在几个 Chrome 版本中,我们能够用纯 CSS 实现它。
:focus:not(:focus-visible){ outline: none;}
(目前有效的 Firefox 兼容解决方案)
:focus:not(:-moz-focusring){ outline: none;}
使用 `e.target.blur()` 时要非常小心。正如你所承认的,仅使用键盘的用户可能需要从页面顶部重新开始(大多数浏览器会从他们离开的地方继续)。对于状态更改很重要的控件(例如切换),屏幕阅读器用户可能也无法收到状态更改的通知。
第二个解决方案更好,但一定要用屏幕阅读器以及键盘(移动设备和桌面设备)进行测试。
以这种方式使用 `e.target.blur` 会对键盘和指针的混合使用产生严重后果。我敢说这对于用户来说是相当不友好的。
通常情况下,你可以用鼠标点击某处,然后键盘的 Tab 键操作会从该点开始。所以你可以做以下事情:
点击打开一个展开组(例如 `details/summary`),然后按 Tab 键转到包含其中的第一个控件。
点击表单中的第一个控件,然后使用 Tab 键继续遍历其他输入框。
点击单选按钮组中的任何一个单选按钮,然后使用箭头键选择正确的按钮。
调用 `blur()` 通常会将键盘 Tab 键操作的位置重置回页面开头。这会让混合使用键盘和指针的人感到困惑。
仅使用键盘的用户,如果发现指针难以或不舒服使用,有时也会使用它,尽管这不是他们首选的交互方式。可能是焦点指示器难以看到,或者 Tab 键操作顺序很混乱。有时只是为了避免大量的 TAB 键操作。特别是,仅使用键盘的用户可能会使用“鼠标键”操作系统功能来发出点击,然后继续使用 Tab 键操作。
有些人主要使用指针,但在处理表单控件时会切换到键盘 Tab 键操作。任何曾经做过数据录入员的人都有可能养成这种习惯。
在我看来,以这种方式使用 `e.target.blur()` 比使用 `outline: none` 更糟糕。CSS 规则只删除了可见的焦点指示器,但不会干扰实际的焦点状态,因此键盘 Tab 键操作的位置不会被打乱。
在 了解 WCAG 成功标准 2.5.6:并发输入机制 中,它指出“用户应该能够在任何时候切换输入机制,如果用户认为某些任务和交互使用另一种输入机制更容易完成” (重点是我加的)。我认为将键盘 Tab 键操作的位置重置回页面开头违背了这一点的精神(尽管在严格的解读中,我认为它没有违反成功标准的规范文本)。
如前所述,在这里使用 `blur()` 仍然可能存在问题。事实上,使用 `:focus-visible`(现在用 https://github.com/WICG/focus-visible 对它进行填充)是最佳选择。
这个技巧很酷,谢谢!:)
上面来自 Alex 的观点是正确的,但我不知道强迫元素进行 `.blur()` 是否是一个好的选择。至少 Firefox 在点击后混合使用时,哪个元素会获得焦点似乎不一致。而且它仍然在点击时“闪烁”焦点环。我还担心强制模糊会导致某些事件处理程序比预期更频繁地触发,或者屏幕阅读器在没有更多测试的情况下不满意——但这只是猜测。你可以在 https://codepen.io/gillibrand/pen/povoZKE 上尝试一个示例。
你可能可以通过文档级别的 onclick/onkeydown 处理程序更好地处理这个问题,这些处理程序可以智能地向 body 添加和删除 “show-keyboard-focus” 类,以便 :focus 选择器只有在该类处于活动状态时才会匹配。
嘿,我只是来这里寻找 `:focus{outline: none}`,因为我不知道你如何做到的。它很有帮助,谢谢。