:focus-visible不能单独使用,必须与:focus配合且:focus在前声明;否则旧浏览器完全忽略样式,导致鼠标点击无反馈、键盘用户失去焦点指示。

:focus-visible 不是 :focus 的升级替代品,而是互补机制——它只在键盘导航时显示焦点样式,而 :focus 无差别响应所有聚焦方式。忽略这点,无障碍体验会直接降级。
为什么:focus-visible不能单独使用
只写 :focus-visible 而不配 :focus,会导致旧浏览器(如 Safari 15.3 及更早、Firefox 83 及更早)完全不渲染任何焦点样式。用户鼠标点击按钮后没反馈,会误以为操作失败;键盘用户 Tab 切换时也看不到焦点位置,失去导航依据。
- 浏览器不支持
:focus-visible时,整条规则被忽略,不会 fallback 到:focus -
:focus是基础保障,:focus-visible是增强判断,二者必须共存 - 顺序错误(比如
:focus-visible写在前面)会让降级逻辑失效:不支持的浏览器连:focus样式都拿不到
:focus 和 :focus-visible 的触发逻辑差异
:focus 是“状态驱动”:只要元素 DOM 中 document.activeElement === element,就匹配,不管怎么来的;:focus-visible 是“行为驱动”:浏览器根据输入源(keyboard vs pointer)动态决定是否激活,且该判断不可 JS 干预。
- 鼠标点击
button→ 触发:focus,但不触发:focus-visible - 按 Tab 键聚焦到同一
button→ 同时触发:focus和:focus-visible - 触摸屏点击 → 多数浏览器不触发
:focus-visible(Safari 15.4+ 默认启用,但需辅助功能开启才稳定) -
element.focus()调用 → 浏览器根据调用上下文智能判断:若前一次交互是键盘,则可能触发:focus-visible;若来自鼠标事件处理器,则通常不触发
安全写法:降级必须靠声明顺序,不是 @supports
用 @supports selector(:focus-visible) 包裹样式块是危险的——Safari 15.3 及更早会直接丢弃整个 @supports 块,导致连 :focus 样式都失效。真正可靠的降级路径只有两条:
立即学习“前端免费学习笔记(深入)”;
- 先写窄范围的
:focus(例如button:focus { outline: none; }),再用同选择器权重的:focus-visible覆盖(例如button:focus-visible { outline: 2px solid #0066cc; }) - 全局重置了
* { outline: none; }?必须显式为:focus-visible恢复outline,否则它也被清掉 - 需要兼容 IE 或老 Android?引入
focus-visiblepolyfill(如npm install focus-visible),它在原生支持时静默退出,不支持时自动接管
容易被忽略的兼容性细节
Safari 对 :focus-visible 的启用依赖系统辅助功能开关:macOS 或 iOS 上若未开启“按下 Tab 键以在网页上进行键盘导航”,即使版本 ≥15.4,:focus-visible 也可能不生效。这不是 bug,是规范要求——浏览器把“键盘导航是否启用”作为判断前提。
- Chrome 86+、Firefox 84+、Edge 89+ 原生支持,无需额外配置
- Safari 15.4+ 支持,但需用户开启辅助功能中的键盘导航选项
- 某些屏幕阅读器组合(如 VoiceOver + Safari)可能绕过浏览器的
:focus-visible判断逻辑,仍依赖:focus提供反馈


















