加 touchstart 监听器可使 ios webview 中 :active 正常触发,因其关闭 300ms 点击延迟;必须用 addeventlistener 绑定空函数并设 { passive: true },且全局仅需执行一次。

直接给 document.body 绑一个空的 touchstart 监听器,就能让 :active 在 iOS Webview(包括微信、QQ、Safari)里正常触发 —— 但必须带 { passive: true },否则 iOS 11+ 会警告甚至禁用监听器。
为什么加 touchstart 就能激活 :active
iOS WebKit 为双击缩放预留了约 300ms 的点击延迟,期间不认定“激活态”,:active 样式自然不更新。绑定 touchstart 是向浏览器声明:“这里要响应触摸”,它就会关闭该区域的延迟机制 —— 这不是 CSS 行为修复,而是绕过底层事件调度卡点。
关键点::active 本身没失效,只是触发时机被压在 touchend 之后;加监听器是提前“解锁”状态链路。
- 只对已绑定
touchstart的元素或其子树生效(所以绑body最省事) - 必须用
addEventListener,ontouchstart=""属性写法在部分 iOS 版本中不可靠 - 回调函数体可以为空,但不能传
null或省略,写成() => {}或function() {}都行
touchstart 监听器必须加 { passive: true }
iOS 11+ 要求所有 touchstart 监听器显式声明 passive,否则控制台报黄色警告:Unable to preventDefault inside passive event listener,滚动可能卡顿,极端情况下监听器会被静默禁用。
正确写法:
document.body.addEventListener('touchstart', () => {}, { passive: true });
- 不要写成
{ passive: false }或漏掉该配置项 -
{ passive: true }意味着你承诺不调用event.preventDefault(),这正符合“空监听器”的语义 - 如果后续需要拦截默认行为(比如阻止缩放),得单独为特定元素加非 passive 监听器,不能复用这个全局空监听
SPA 页面里重复绑定会出问题
单页应用路由切换时,若每次都在 mounted 或 useEffect 里重新执行 addEventListener,而没对应 removeEventListener,会导致监听器堆积 —— 虽然空函数影响小,但违背事件管理原则,且某些老版本 WebView 可能因此触发异常。
- 推荐在应用初始化阶段(如
main.js或内脚本)执行一次即可 - Vue 项目可用
onBeforeMount+ 全局标记判断是否已绑定 - React 项目建议放在
index.html的<script></script>中,早于 React 渲染执行 - 避免在组件级反复操作
body事件,这是跨组件副作用,应收敛到入口层
真正容易被忽略的是:这个修复只解决 :active 触发时机,不解决样式本身兼容性。比如 button:active 在某些 iOS Webview 里仍可能因重绘策略不触发背景色变化,此时需配合 -webkit-transform: translateZ(0) 强制硬件加速,或改用 opacity 等更稳妥的过渡属性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











