outline: none 无效因 bootstrap 焦点样式依赖 box-shadow 而非 outline;需同步清除 .btn:focus、:active:focus、.active:focus 的 box-shadow;:focus-visible 默认仅响应键盘 tab,须与 :focus 配合使用并确保层叠顺序;移除默认焦点样式后必须提供替代视觉反馈(如 border 或调整后的 box-shadow)以保障可访问性。

只写 outline: none 为什么没用
因为 Bootstrap 的按钮焦点样式主要靠 box-shadow 实现,不是靠 outline。你删了 outline,但 box-shadow: 0 0 0 0.2rem rgba(13, 110, 237, 0.25) 还在,蓝色光晕照常出现。更麻烦的是,这个阴影同时作用于 :focus、:active:focus、.active:focus 多个状态——只覆盖一个,松手瞬间就露馅。
常见错误写法:.btn:focus { outline: none; }
结果:鼠标点下去正常,一松手蓝框立刻弹出来。
- 必须同步清掉所有相关状态的
box-shadow,至少包括.btn:focus、.btn:active:focus、.btn.focus - 如果用了
.btn-primary等变体,还要确认它们的:hover和:focus规则没更高权重把你覆盖掉 - Bootstrap v5.3+ 中
--bs-btn-focus-box-shadow变量只影响:focus-visible,改它对:focus无效
:focus-visible 为什么完全没反应
不是你写错了,是浏览器行为和 Bootstrap 默认逻辑打架::focus-visible 默认只对键盘 Tab 触发生效,而鼠标点击后触发的是 :focus;但 Bootstrap 已用 outline: 0 把 :focus 的视觉反馈干掉了,又没给 :focus-visible 补上——结果就是:Tab 不亮、点也不亮,按钮像“失焦”了一样。
- 必须同时声明
.btn:focus(兜底,兼容老浏览器 + 防布局跳动)和.btn:focus-visible(支持时叠加精准反馈) -
:focus-visible必须写在:focus后面,靠层叠覆盖;否则 Safari 15.4 之前等不支持该伪类的浏览器会整条忽略,而:focus又没定义,按钮彻底“看不见焦点” - 别用
.btn:focus:not(:focus-visible)隐藏鼠标焦点——这会把 JS 主动调用的button.focus()也干掉
移除之后键盘用户就“瞎了”
这是最常被跳过的一步:移掉默认轮廓后,仅靠键盘操作的人根本不知道当前焦点在哪,直接违反 WCAG 2.1。不能只做“清除”,必须提供替代视觉反馈。
- 推荐方案:给
.btn:focus加border: 2px solid #0d6efd,或微调原版阴影为box-shadow: 0 0 0 0.2rem rgba(13, 110, 237, 0.25)(透明度不变,只是明确写出) - 深色模式下注意对比度,
#0d6efd在深背景上可能不够显,可加@media (prefers-color-scheme: dark)单独调色 - 别用
background-color做唯一反馈——按钮本身颜色变化太弱,尤其小尺寸按钮,键盘用户很难分辨
移动端点击态(:active)为啥没反馈
鼠标按下时 :active 和 :hover 同时生效,但 Bootstrap 的 :active 规则里常含 transform: none,强行抵消了 :hover 的位移效果,导致“按下去像没按”。iOS 上更明显,因为默认 :active 持续时间极短。
- 纯 CSS 方案有限:加
touch-action: manipulation能略微延长 iOS 的:active时间,但不可靠 - 真正可控的做法是用 JS 监听
mousedown/touchstart和mouseup/touchend,动态切换is-pressed类,再用 CSS 控制该类下的box-shadow或transform - 避免在
:active里改background-color——色值变化不如阴影或位移反馈直观,且易和:hover冲突
:focus 和 :focus-visible 的配对声明,以及移除轮廓后没补替代反馈。这两步不做,按钮看似“干净”了,实则把可访问性缺口撕得更大。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











