必须覆盖 .btn:focus、.btn:active:focus、.btn.active:focus、.btn.focus、.btn:active.focus 全部伪类组合,因不同交互路径触发的焦点状态各异,漏掉任一都会导致蓝边闪现。

为什么只写 .btn:focus { outline: none } 不生效
因为 Bootstrap 的“蓝色边框”不是单靠 outline 实现的,而是 outline + box-shadow 双重叠加效果。Chrome 89+ 还会用 outline-style: auto 渲染焦点环,它不响应 outline: none。只清 outline,box-shadow 仍在;只清 box-shadow,旧版 Firefox 仍 fallback 显示原生轮廓。
必须覆盖的全部伪类组合有哪些
不同交互路径触发的焦点状态不同,漏掉任一组合都可能在特定操作下闪出蓝边:
-
.btn:focus:Tab 进入或鼠标点击后获得焦点 -
.btn:active:focus:鼠标按下松手前那一帧(最常被忽略的“闪一下”元凶) -
.btn.active:focus:带active类的 toggle 按钮(如下拉、折叠) -
.btn.focus和.btn:active.focus:Bootstrap 4 及更早版本 JS 动态添加的 class,未覆盖会导致部分组件失效
如何安全地移除又不破坏可访问性
直接全局禁用 outline 会让键盘用户完全失去焦点感知,违反 WCAG 2.1 AA 标准。稳妥做法是「替换」而非「删除」:
- 对鼠标操作后的临时焦点,用
:focus:not(:focus-visible) { outline: none; }拦截(Bootstrap 5+ 默认启用,但需确认未被自定义 CSS 覆盖) - 为
button:focus补一个替代视觉反馈,例如box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); - iOS Safari 15.4 之前不支持
:focus-visible,所以双保险必须同时存在 - 别用
outline: 0—— Safari 下可能残留渲染异常
其他可聚焦元素也得同步处理
按钮不是唯一受害者。所有可聚焦元素共享同一套焦点机制,漏掉它们会导致体验割裂:
立即学习“前端免费学习笔记(深入)”;
-
.form-control:focus:普通输入框 -
.custom-select:focus:Bootstrap 自定义下拉框 -
.custom-checkbox input:focus + .custom-control-label:label 包裹的 checkbox/radio - 第三方插件(如
bootstrap-select)的触发按钮,需查其文档看是否暴露了focus-visible类名
真正难的不是写对 CSS,而是确保键盘用户在任意操作路径下,都能清晰知道当前焦点落在哪个元素上——这点上线前很容易被跳过,但无障碍审计时大概率是高危项。


















