:focus-visible单独写没反应,因为浏览器仅在Tab、Shift+Tab、方向键、Enter、Space等键盘导航时触发它,鼠标点击、触摸、JS focus()均不匹配;且Safari 15.3及更早版本会忽略该规则,必须搭配:focus兜底并确保:focus在前声明。

为什么:focus-visible单独写没反应
浏览器只在 Tab、Shift+Tab、方向键、Enter、Space 这类键盘导航行为下才匹配 :focus-visible;鼠标点击、触摸、甚至 JS 调用 element.focus() 都不会触发它。所以如果你只写 button:focus-visible { outline: 2px solid #007aff; },鼠标点按钮后页面完全没反馈——这不是 bug,是设计如此。
更关键的是兼容性:Safari 15.3 及更早版本会直接忽略整条 :focus-visible 规则。没兜底,就等于全军覆没。
- 别用
*:focus { outline: none; },它会把:focus-visible的基础能力一起干掉 - 必须显式设置可感知样式,比如
outline或box-shadow,不能只依赖浏览器默认 - DevTools 里手动勾选元素的
:focus-visible状态,比反复切键盘更快验证是否生效
正确的声明顺序和基础样式怎么配
:focus 是兜底层,:focus-visible 是增强层,二者不是替代关系,而是降级路径。顺序错了,旧浏览器就看不到任何焦点提示。
- ✅ 正确写法:
button:focus { outline: 1px dotted #999; }在前,button:focus-visible { outline: 2px solid #007aff; outline-offset: 2px; }在后 - ❌ 错误写法:
:focus-visible写在:focus前面;或两者都加!important导致层叠混乱 -
outline-offset: 2px很关键——工具栏图标间距常小于 4px,不加容易和相邻元素粘连
哪些元素默认不触发:focus-visible,怎么补救
加了 tabindex="0" 不等于能用。浏览器根据语义和交互意图判断是否启用该伪类,常见“假可聚焦”场景需要额外处理:
立即学习“前端免费学习笔记(深入)”;
<div role="button">:必须监听 <code>keydown,显式响应Enter和Space,否则 Chromium 可能判定为“非交互意图”- 自定义
contenteditable容器:它自身不触发:focus-visible,需手动加tabindex="0",并在focusin中用 JS 切换.focus-visible类模拟 -
<select></select>用了appearance: none:部分浏览器会丢弃原生焦点样式,得手动给select:focus-visible补outline - 禁用态(
aria-disabled="true"或disabled):即使有tabindex="0",也不会匹配:focus-visible——这是正确行为,别强行绕过 - Chrome 111+ 支持
element.focus({ focusVisible: true }),可强制触发:focus-visible - 旧版浏览器或跨浏览器场景下,建议改用
element.focus(); element.classList.add('focus-visible');+ 对应 CSS 类模拟 - 如果用了框架(如 React 封装的按钮),检查它是否悄悄调用了
focus()却没传focusOptions
JS 聚焦时:focus-visible不生效怎么办
页面加载后 JS 调用 element.focus() 默认不算键盘导航,:focus-visible 不匹配。这是最隐蔽也最容易被忽略的一环。


















