在body上加touchstart监听器并非修复:active,而是通过标记页面支持触摸交互来放宽激活限制;更优解是为目标元素添加ontouchstart=""属性,并配合role="button"、tabindex="0"及关闭-webkit-tap-highlight-color。

为什么在 body 上加 touchstart 能“修复” :active?
这不是修复,是触发机制绕过。iOS Safari 默认只对「有交互意图」的元素启用 :active,而给 body 绑一个空 touchstart 监听器(哪怕函数体为空),会让整个页面被浏览器标记为“支持触摸交互”,从而放宽对子元素 :active 的激活限制。
但要注意:这个技巧仅在部分旧版 iOS WebView 或未声明 viewport 的页面中有效;现代 iOS Safari(15+)已基本不买账,且它无法解决元素自身不可聚焦、pointer-events: none 或父容器 overflow: hidden 截断反馈等问题。
ontouchstart="" 比 body 监听更直接有效
比起全局监听,给目标元素加 ontouchstart=""(空字符串属性)是更轻量、更可控的做法。它不需要 JS,也不污染全局,浏览器看到该属性就认为“此元素要响应触摸”,立刻激活 :active 的即时渲染流程。
- 适用于
<div>、<code><span></span>等默认不可点击元素 - 必须配合可聚焦能力才稳定:若元素无
tabindex="0"或不是原生可点击标签(如<button></button>),首次触摸仍可能延迟 - 不要和
event.preventDefault()同时用——它会中断:active的状态链 - 元素本身加
role="button"和tabindex="0"(保障可访问性 + 焦点能力) - 加
ontouchstart=""(显式声明触摸意图) - CSS 中确保
:active样式有足够对比度,并带transition:例如background-color 0.1s, transform 0.05s
真正跨端稳定的最小配置组合
单靠一个技巧很难 100% 覆盖所有机型和系统版本。实测最稳妥的写法是三者共存:
漏掉任意一项,都可能在某台 iPhone 或某款定制安卓浏览器里完全没反馈。
别忽略 -webkit-tap-highlight-color 的干扰
即使 :active 触发了,iOS 默认的半透明灰色高亮层(-webkit-tap-highlight-color)会盖在你的样式上,造成“点了但颜色不对”或“闪一下又变回来”的错觉。
必须显式关闭它:
button, [role="button"] { -webkit-tap-highlight-color: transparent; }
注意:不能只写 * { -webkit-tap-highlight-color: transparent; },否则会影响 <input type="text"> 等表单控件的光标定位体验。
真机测试时最容易忽略的,是把 :active 当成持久状态来用——它只存在几十毫秒,手指一抬就没了。需要明确反馈位置(比如列表项高亮)或长按逻辑,必须用 JS 控制类名,而不是死磕伪类。











