:focus-visible 不能单独使用,必须与 :focus 共存且 :focus 声明在前;因其仅响应键盘导航行为,鼠标点击等不触发,旧版 Safari 会忽略该规则,需用 polyfill 或渐进增强确保兼容。

只写 :focus-visible 会直接让鼠标用户失去焦点反馈,键盘用户在旧浏览器里也看不到任何提示——必须和 :focus 共存,且 :focus 必须声明在前。
为什么不能单独用 :focus-visible?
浏览器对 :focus-visible 的触发有明确限制:它只响应 Tab、Shift+Tab、方向键、Enter、Space 这类键盘导航行为;鼠标点击、触摸 tap、甚至 JS 调用 element.focus() 都不会匹配它。
- 只写
button:focus-visible { outline: 2px solid blue; }→ 鼠标点按钮后完全没轮廓,用户无法确认操作是否生效 - Safari 15.3 及更早版本会直接忽略整条
:focus-visible规则,结果是所有浏览器都看不到焦点样式 -
:focus是兜底基础,:focus-visible是增强层,二者不是替代关系
:focus 和 :focus-visible 的声明顺序怎么写?
顺序错了,降级逻辑就崩了。浏览器不支持 :focus-visible 时会整条规则丢弃,但前面的 :focus 仍有效——前提是它写在前面。
- ✅ 正确:
button:focus { outline: none; }在前,button:focus-visible { outline: 2px solid #0066cc; }在后 - ❌ 错误:
:focus-visible写在:focus前面,或用!important强行覆盖 - 如果全局写了
* { outline: none; },必须显式为:focus-visible恢复outline,否则它也被清掉
哪些元素默认触发 :focus-visible?
不是加了 tabindex="0" 就能用。浏览器根据语义和交互模式内置判断逻辑:
立即学习“前端免费学习笔记(深入)”;
- ✅ 默认支持:
<input>、<textarea>、<button>、<select>、带tabindex="0"的<div> - ❌ 默认不触发:
<a>(无href)、<label>(未设tabindex)、纯<div role="button">(缺键盘事件监听) - 验证技巧:DevTools 里手动勾选元素的
:focus-visible状态,比反复切键盘更快确认样式是否生效
兼容性差怎么办?别碰 @supports selector()
@supports selector(:focus-visible) 在 Safari 15.3 及更早版本中解析失败,整个 CSS 块会被丢弃——你连降级样式都拿不到。
- 真正可行的路径只有两个:引入
focus-visiblepolyfill(它在支持原生特性时静默退出),或坚持「渐进增强」写法::focus兜底 +:focus-visible覆盖 - Safari 15.0–15.3 需手动开启辅助功能才启用原生,行为不稳定,polyfill 是最省心的选择
- 特别注意:表单控件如
<input>在获得焦点时,即使由鼠标触发,也应有视觉反馈(例如光标闪烁+边框高亮),不能一概套用:focus-visible
最容易被忽略的一点是:自定义组件(比如 <div role="button">)必须同时满足三件事才能可靠触发 :focus-visible —— 加 tabindex="0"、绑定键盘事件(keydown 监听)、且确保首次聚焦来自键盘导航而非鼠标点击。


















