:active 仅在按下瞬间生效,适合模拟物理按压感;:focus 持续存在直至焦点移除,用于键盘导航反馈——二者语义与时机不同,不可混用。

:active 是按下瞬间的视觉反馈,:focus 是键盘导航或点击后持续存在的焦点状态——两者不能互换,混用会导致交互逻辑错乱。
按钮按下时凹陷效果该用 :active 而不是 :focus
用户鼠标左键按住、触屏长按、或按空格/回车触发按钮时,:active 仅在「按下→释放」这一帧内生效;松手即消失。它适合模拟物理按压感,比如背景变深、边框内缩、轻微 transform: scale(0.98)。
-
:focus不会因松开鼠标而消失,只要没被其他操作移走焦点(比如 TAB 切走、点击别处),样式就一直挂着 - 如果误用
:focus实现“按下反馈”,用户点完按钮后焦点仍保留,视觉上像按钮卡在“已按”状态 -
:active对所有元素都有效,不需要额外属性;:focus默认只对<button></button>、<a></a>、<input>等可聚焦元素起作用
:focus 在按钮上默认生效,但要注意样式叠加顺序
原生 <button></button> 自带焦点能力,所以 button:focus 无需 tabindex 就能响应。但 CSS 声明顺序直接影响最终表现:
- 必须按
:focus→:hover→:active的顺序写,否则:hover可能覆盖:focus,导致键盘用户 TAB 进来时看不到焦点轮廓 - 常见错误:把
:active放最前面,结果点击时:focus样式(比如outline)盖住了你设计的凹陷效果 - 不要直接
outline: none,除非用box-shadow或border提供同等对比度的替代焦点指示
非表单元素加 :focus 必须显式设 tabindex
像 <div> 或自定义组件按钮,即使绑了 <code>click 事件,:focus 也默认不生效——因为它们没有原生焦点能力。
- 加
tabindex="0"后,该元素才能被 TAB 键选中,:focus才起作用 - 加
tabindex="-1"则只能通过 JS.focus()主动聚焦(比如模态框关闭按钮),不会进入 TAB 导航流 - 一旦加了
tabindex,就必须同步处理Enter和Space键触发逻辑,否则键盘用户无法操作,损害可访问性
想让按钮“点击后保持高亮”?别靠 :active 或 :focus
:active 持续时间太短,:focus 又依赖焦点生命周期——两者都不适合表达“已选中”“已激活”这类语义状态。
- 正确做法是用 JS 切换 class,比如点击后加
is-active,再配.btn.is-active { background: #0056b3; } - 若需 ARIA 语义支持(如开关、标签页),优先用
[aria-pressed="true"],而不是硬塞:focus - 特别注意:某些浏览器对
button:focus有约 3 秒延迟才显示 outline,这会让键盘用户的反馈显得滞后,:focus-visible是更现代的替代方案
真正容易被忽略的是::focus 不只是“样式问题”,它绑定着键盘导航路径和屏幕阅读器播报逻辑;而 :active 的生效时机极短,动画过渡时间超过 100ms 就可能错过这个窗口。这两个伪类背后,其实是两套完全不同的用户操作模型。











