移动端:active失效是因WebKit仅对语义化可交互元素(如button、a)启用该状态,div需补role="button"+tabindex="0"或改用button;须加ontouchstart=""、touch-action:manipulation和-webkit-tap-highlight-color:transparent方可生效。

:active 在移动端“失效”,不是 CSS 写错了,而是浏览器压根没让它进入激活流程——iOS Safari 和主流 WebView 默认跳过普通元素的 :active 计算,除非你明确声明“这个区域要响应触摸”。
为什么 div.btn:active 在真机上完全没反应
WebKit(iOS Safari 底层)只对语义化可交互元素(如 <button></button>、<a></a>)启用 :active 状态栈。一个纯 <div> 即使加了 <code>onclick 或 CSS cursor: pointer,也不会被识别为“激活目标”。现象是样式写了但 DevTools 里都看不到 :active 高亮标记。
- 必须补语义:用原生
<button type="button"></button>最省事;若必须用<div>,至少加 <code>role="button"+tabindex="0" - 父容器设了
pointer-events: none或overflow: hidden会截断 touch 事件流,导致子元素根本收不到触发 -
ontouchstart=""是 HTML 层面最轻量的“开关”——iOS 12+ 稳定支持,比 JS 绑定body.addEventListener('touchstart', ...)更可靠且无内存泄漏风险 - 给按钮元素加
touch-action: manipulation——告诉浏览器“这里只点按,别等双击、别缩放”,能提前激活点击态链路 - 加
-webkit-tap-highlight-color: transparent——干掉系统蓝框,否则你的background-color或transform反馈会被遮盖 - 慎用
background-color做反馈:低端安卓上颜色过渡易跳变;推荐transform: scale(0.98)或opacity: 0.8,更稳且不触发布局重排 - 监听
touchstart添加is-pressed,并在touchend、touchcancel、touchleave中移除——touchcancel必须处理,否则手指滑出区域后状态残留 - 不要用
click替代:它有 300ms 延迟,且无法捕捉“按住”过程,用户松手才触发,压感断层 - 目标元素需是
button、a或带role="button"的元素,否则event.target.closest()匹配不到 - :active 适合模拟物理按压感(如
transform: scale(0.98)) - :focus 只该用于键盘导航或明确需要持久高亮的场景
- 若需“点击后保持选中”,必须用 JS 切换
is-active类,而非依赖任一伪类
必须加的两条关键 CSS 规则
:active 在 iOS 上持续时间极短(约 60–100ms),且默认蓝框(-webkit-tap-highlight-color)会盖掉你的样式。不处理这两条,再准的 :active 也白写。
JS 手动接管 is-pressed 类比 :active 更可靠
当列表项含图片、图标或嵌套链接时,纯 CSS :active 极易被滚动中断或语义识别失败。此时监听 touchstart/touchend 切换自定义类是最稳方案。
立即学习“前端免费学习笔记(深入)”;
:active 和 :focus 别混用,尤其在 iOS 首次点击时
:active 是瞬时态(手指按住即生效,一抬就消失);:focus 是持续态(焦点不移走就一直挂着)。很多项目写 button:hover, button:focus { ... },结果 iOS 首次点击只触发 :focus,样式卡住,再点才响应——这不是 bug,是伪类语义错配。
真正麻烦的不是写法,是测试时只在自己设备上点一下就认为“没问题”。不同 iOS 版本、微信/支付宝 WebView、Android Chrome 对 :active 的策略差异很大,跨端一致的最小可行方案永远是:用 <button></button> 替代 <div>,或三者齐备——<code>role="button" + tabindex="0" + ontouchstart=""。


















