:focus-visible单独使用无效,因仅在Tab/Enter等键盘导航时触发,鼠标点击、触摸或JS聚焦均不匹配;真正起作用的是:focus:not(:focus-visible)组合选择器,需按:focus、:focus:not(:focus-visible)、:focus-visible顺序声明。

为什么只写 :focus-visible 没用
浏览器只在明确的键盘导航行为(Tab、Shift+Tab、Enter、Space)下才匹配 :focus-visible;鼠标点击、触摸 tap、甚至 JS 调用 element.focus() 都不会触发它。所以单独写 button:focus-visible { outline: none; } 完全无效——DevTools 里这条规则直接变灰禁用,蓝框照旧出现,你还以为是兼容性问题。
:focus:not(:focus-visible) 才是真正起作用的选择器
它专门捕获“有焦点但非键盘触发”的情况,也就是鼠标点击后你想隐藏轮廓的那一刻。但必须配合正确的声明顺序,否则降级失效:
-
:focus必须写在最前面,定义基础焦点样式(比如统一用outline: 2px solid #007aff;) -
:focus:not(:focus-visible)紧跟其后,对鼠标/触摸场景做清除(outline: none;) -
:focus-visible写在最后,给键盘用户显式提供轮廓(outline值不能为0或空,否则不生效)
错误示例:button:focus-visible { outline: none; } button:focus { outline: 2px solid blue; } → 旧浏览器里 :focus 被前面无效规则压制,焦点彻底不可见。
哪些元素上 :focus-visible 根本不会触发
不是所有加了 tabindex="0" 的元素都支持。浏览器按语义和交互模式内置判断逻辑:
- ✅ 默认支持:
<input>、<textarea></textarea>、<button></button>、<select></select>、带tabindex且含role="button"的<div> <li>❌ 基本不触发:<code><a></a>(无href)、<span></span>(哪怕写了tabindex="0")、<img>(本身不可聚焦) - ⚠️ 自定义组件要小心:用
<div tabindex="0"> 模拟按钮,但没加 <code>role或没监听Enter/Space,旧 Safari 可能跳过:focus-visible<img>点击出蓝框?那其实是父容器(如<a></a>或<button></button>)在聚焦,得在它上面写规则,而不是对<img>本身操作。iOS 上的半透明蓝 overlay 不是
:focus问题你在 iPhone 上点按钮看到的蓝色遮罩,和
:focus或:focus-visible完全无关——这是 WebKit 的-webkit-tap-highlight-color行为。解决方式是单独处理:-webkit-tap-highlight-color: transparent;。这个样式和焦点逻辑并行,互不影响,漏掉它会导致点击反馈混乱。











