:focus-visible更可靠,因它仅在tab、shift+tab、enter、space等键盘导航时生效,而:focus对鼠标点击、触摸、js聚焦均触发蓝框造成干扰;需禁用全局outline: none并显式设置outline样式,且声明顺序应为:focus先设基础样式、:focus-visible后覆盖。

为什么:focus-visible比:focus更可靠
:focus一触发就画轮廓,鼠标点、触摸点、JS调用element.focus()全算——但用户根本没按键盘,这时候蓝框只是干扰。而:focus-visible是浏览器自己判断“这次聚焦是不是键盘驱动的”,只在Tab、Shift+Tab、Enter、Space等真实键盘导航时生效。
怎么写才能让:focus-visible真正显示出来
直接写:focus-visible样式大概率没反应,关键在两件事:
- 别用
* { outline: none }这种全局清空,它会把:focus-visible的基础能力一起干掉 - 必须显式设置
outline或其他可感知样式,比如outline: 2px solid #007aff和outline-offset: 2px - 声明顺序不能错:先写
button:focus { outline: none; },再写button:focus-visible { outline: 2px solid #007aff; }——靠层叠降级,不是靠!important
哪些元素默认不触发:focus-visible
加了tabindex="0"不等于能用,浏览器有内置逻辑:
- ✅ 默认触发:
<input>、<textarea></textarea>、<button></button>、<select></select>、带tabindex="0"的<div> <li>❌ 默认不触发:<code><a></a>(无href)、<span></span>(即使有tabindex="0")、<label></label>(除非显式设tabindex) - ⚠️ 自定义组件(如
<div role="button">)必须配<code>role+ 键盘事件监听,否则部分浏览器拒绝激活兼容性坑和调试捷径
:focus-visible在Chrome 86+、Firefox 89+、Safari 15.4+原生支持;Safari 15.3及更早版本不识别,且旧版行为不稳定。更隐蔽的问题是:很多CSS框架或重置库(如旧版Bootstrap)悄悄覆盖了它的默认行为。调试时别反复切键盘,直接在DevTools里手动勾选元素的
:focus-visible状态,看样式是否生效——这是最快验证方式。最常被忽略的点:页面加载后JS调用
element.focus()默认不算键盘导航,:focus-visible不匹配;若需强制触发,得用element.focus({ focusVisible: true })(Chrome 111+支持)。











