:focus-visible 在旧版浏览器中被直接忽略,必须用 js-focus-visible polyfill 实现兼容;需改写 css 为类选择器并添加降级规则;自定义元素须设 tabindex 和 aria role 并处理键盘事件。

旧版浏览器根本不认识:focus-visible语法
这不是写法错误,而是浏览器解析器直接忽略整条 CSS 规则。Chrome 86 以下、IE 全系、Safari 15.3 及更早版本、部分企业定制内核浏览器,压根不识别 :focus-visible 这个伪类——它就像写了一个不存在的属性,CSS 引擎跳过执行,连降级逻辑都不会触发。
为什么不能用:focus简单替代
:focus 和 :focus-visible 语义完全不同::focus 只管“有没有焦点”,:focus-visible 管“怎么获得的焦点”。直接替换会导致:
- 鼠标点击按钮时也显示 outline,干扰视觉动效
- 违背可访问性原则——键盘用户需要提示,鼠标用户不需要
- 屏幕阅读器用户可能依赖更精细的焦点上下文,粗暴降级会丢失意图信息
必须用 js-focus-visible Polyfill 补逻辑
手写 JS 模拟几乎必然失败,真正可靠的只有 js-focus-visible:
- 它体积小(约 2KB gzip),兼容 IE11 到 Chrome 49,不依赖
MutationObserver - 核心逻辑是监听首次键盘操作(Tab、Shift+Tab、方向键等),在
上加js-focus-visible类,并给当前聚焦元素加focus-visible类 - CSS 必须改写为类选择器:
button:focus-visible, button.js-focus-visible .focus-visible - 必须加降级规则:
button:focus:not(.js-focus-visible .focus-visible) { outline: none; },否则旧版 Chrome 会回退到默认 outline
自定义元素容易漏掉支持
即使引入了 Polyfill,div、span 或封装组件也不会自动获得 :focus-visible 行为:
- 必须设
tabindex="0",且有明确 ARIA role(如role="button") - 必须监听
onkeydown并处理 Enter/Space,否则浏览器认为“不响应键盘”,跳过判断 - 不能被
pointer-events: none或visibility: hidden阻断聚焦链 - 移动端 Safari 在 JS 调用
.focus()且无真实用户手势时,压根不触发 focus 事件——Polyfill 内部已处理,手写很难覆盖
真正难的不是加一行 <script></script>,而是确保所有可聚焦元素——包括 React Button、Web Component、tabindex="0" 的 div——都被正确识别。这点漏掉,键盘用户就彻底失焦了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











