:focus-visible 仅响应键盘触发的焦点,是 :focus 的子集;旧浏览器如 Safari 15.3 及更早会直接丢弃该规则,需用 polyfill 或“:focus 兜底 + :focus-visible 覆盖”渐进增强方案。

focus-visible 只响应键盘导航,focus 无条件响应
浏览器判断 :focus-visible 是否匹配,依据的是用户**如何触发焦点**,不是“有没有焦点”。按 Tab、Shift+Tab、方向键、Enter、Space 等键盘行为才会激活它;鼠标点击、触摸 tap、JS 调用 el.focus()、autofocus 都不会触发 :focus-visible。而 :focus 只看“是否获得焦点”,不管来源——只要元素当前是 document.activeElement,它就生效。
这意味着:
- 只写
button:focus-visible { outline: 2px solid blue; }→ 鼠标点按钮后完全没视觉反馈 - 只写
input:focus { border-color: #007bff; }→ 输入框鼠标点开、键盘 tab 进来、JS 聚焦,全都有边框变化 -
:focus-visible是:focus的子集,不是替代关系
为什么:focus-visible在旧浏览器里直接失效?
:focus-visible 在 Safari 15.3 及更早版本中会被整个 CSS 规则块忽略(不是降级,是丢弃)。Chrome 86+、Firefox 83+、Safari 15.4+ 才原生支持。更麻烦的是:@supports selector(:focus-visible) 在 Safari 15.3 及更早也会解析失败,导致整段样式被跳过——你连兜底都拿不到。
真正可行的兼容方案只有两个:
- 用
focus-visiblepolyfill(比如 WICG 的官方版),它在原生支持时静默退出 - 坚持「
:focus兜底 +:focus-visible覆盖」的渐进增强写法,且:focus必须写在前面
哪些元素默认能触发:focus-visible?
不是所有带 tabindex="0" 的元素都能自动触发 :focus-visible。浏览器根据语义和交互模式内置判断逻辑:
- ✅ 默认支持:
、、、、带tabindex="0"的- ❌ 默认不触发:
(无href)、(未设tabindex)、(缺键盘事件监听)特别注意:
类表单控件即使由鼠标触发焦点,也必须有视觉反馈(如边框高亮、光标闪烁),所以不能全靠:focus-visible——得保留:focus控制输入态。容易踩的坑:顺序、outline 和 autofocus
三个高频翻车点:
-
顺序错了就全崩:必须
button:focus { outline: none; }写在前,button:focus-visible { outline: 2px solid #0066cc; }写在后。否则不支持的浏览器会把整条:focus-visible规则丢掉,而后面那条:focus又被前面无效规则“遮住”,结果焦点彻底不可见 -
全局清了 outline 就全没:如果写了
* { outline: none; },那:focus-visible的outline也会被干掉,必须显式恢复,比如加button:focus-visible { outline: 2px solid #0066cc; } -
autofocus 不触发 focus-visible:页面加载时自动聚焦,浏览器不认为这是“键盘触发”,
:focus-visible不会匹配——这种场景必须靠:focus保证反馈
调试时别反复切键盘,用 DevTools Elements 面板手动勾选元素的
:focus和:focus-visible状态,更快验证实际行为。 - ❌ 默认不触发:
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











