button:focus-visible没反应是因为它仅在键盘导航(tab/enter/space)时触发,鼠标点击不匹配;“蓝框”实为:focus生效,需同时声明:focus(兜底)和:focus-visible(强化键盘路径),且:focus必须在前。

button:focus-visible 为什么没反应?
写了 button:focus-visible { outline: none; } 却发现点击按钮时蓝框还在——这不是兼容性问题,是它压根没匹配上。:focus-visible 只在键盘导航(Tab、Shift+Tab、Enter、Space)时触发,鼠标点击、触摸、甚至 JS 调用 element.focus() 都不会激活它。所谓“点击出蓝框”,实际是 :focus 在起作用。
必须同时写 :focus 和 :focus-visible,且顺序不能错
只写 :focus-visible 会导致鼠标用户完全失去焦点反馈;Safari 15.3 及更早版本还会直接忽略整条规则,导致所有用户都看不到轮廓。正确做法是:
-
button:focus在前,提供轻量兜底样式,比如outline: 1px dotted #999;或box-shadow: 0 0 0 2px rgba(0,118,255,0.2); -
button:focus-visible在后,强化键盘路径,必须带outline-offset: 2px;,避免和相邻元素粘连 - 绝对不要把
:focus-visible写在:focus前面,否则旧浏览器里焦点会彻底不可见
哪些地方一写就失效?
常见硬性失效点:
- 全局写了
*:focus { outline: none; }→ 后续所有:focus-visible的outline都被干掉 - 给
img或无语义的div直接写:focus-visible→ 它们默认不触发该伪类,哪怕加了tabindex="0" - 自定义按钮用了
<div role="button"> 却没监听 <code>keydown并响应Enter/Space→ Chromium 可能判定为“非交互意图”,跳过伪类 - 漏掉
outline-offset: 2px→ 圆角按钮的轮廓容易贴边、和 border 重叠,视觉上像没生效
iOS 上的蓝色遮罩不是 :focus-visible 能管的
iPhone 点按钮时看到的半透明蓝 overlay,是 WebKit 的 -webkit-tap-highlight-color 行为,和焦点逻辑无关。要关掉它,得单独加:
a, button, [onclick] {
-webkit-tap-highlight-color: transparent;
}
这个设置不影响 :focus 或 :focus-visible 的任何行为,只是移除瞬时点击高亮。别指望用焦点伪类去覆盖它。
最常被忽略的是:页面加载后 JS 主动调用 element.focus() 默认不算键盘导航,:focus-visible 不会匹配;如需强制触发,得用 element.focus({ focusVisible: true })(仅 Chrome 111+ 支持)。











