不能只写:focus-visible,必须搭配:focus:not(:focus-visible)使用且顺序正确;因:focus-visible仅响应键盘导航,鼠标点击不触发,单独使用无法隐藏鼠标焦点轮廓,且需:focus兜底并避免全局outline重置破坏基础链路。

直接结论:不能只写 :focus-visible,必须搭配 :focus:not(:focus-visible) 一起用,且顺序不能错。
为什么单独写 button:focus-visible { outline: none; } 没用
浏览器根本不会在鼠标点击时触发 :focus-visible —— 它只在键盘导航(Tab/Shift+Tab/Enter/Space)时匹配。这条规则等于没写,蓝框照常出现。更糟的是,你可能误以为是兼容性问题,其实只是逻辑没搭对。
-
:focus-visible不是“开关”,而是浏览器根据交互历史动态判断的伪类;鼠标点击、触摸、el.focus()都不满足触发条件 - 如果全局写了
*:focus { outline: none; },那:focus-visible就彻底失去作用基础——它需要先有:focus才能叠加判断 - Chrome 86+、Safari 15.4+ 原生支持,但 Safari 对首次点击或触控板点按仍可能短暂触发,不能依赖“绝对不触发”
:focus:not(:focus-visible) 是关键降级手段
真正控制鼠标点击时不显示轮廓的,是这个组合伪类。它匹配“获得焦点但不是键盘触发”的所有情况,适合统一清除 outline。
- 写法必须是:
button:focus:not(:focus-visible) { outline: none; },顺序紧接在button:focus之后 - 不能反过来写
button:focus-visible在前,否则会被后续的:focus规则覆盖(CSS 层叠优先级相同,后声明者胜出) - 对自定义组件(如
div[role="button"]),必须带tabindex="0",否则:focus-visible根本不生效 - 避免在重置 CSS 中写
*:focus { outline: none; },它会直接废掉整个链条
键盘用户的轮廓必须显式声明
:focus-visible 不会继承 :focus 的 outline,空规则或 outline: 0 都不算有效样式——它要求你明确告诉浏览器“这里要画什么”。
- 正确写法:
button:focus-visible { outline: 2px solid #007aff; outline-offset: 2px; } - 不要加
!important,它会干扰高对比度模式下的系统焦点样式 - Firefox 默认启用,但旧版需手动开启
about:config → focusring.visible;实际项目建议统一走 polyfill 或忽略其原生行为 - autofocus 元素或 JS 调用
input.focus()默认不触发:focus-visible,如需支持,得用element.focus({ focusVisible: true })(Chrome 111+)
最难的不是写对这三行 CSS,而是确保没有其他样式提前干掉了 :focus 的基础能力——检查 DevTools 的 Computed Styles,确认 outline 真正在 :focus 下存在,再看它是否被 :focus:not(:focus-visible) 正确覆盖。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











