touch-action 是唯一能从根源上关闭移动端 300ms 点击延迟的原生方案;设为 manipulation 可禁用双击缩放并保留滚动与点击,适用于自定义点击容器,原生可点击元素默认已优化。

移动端点击延迟不是JavaScript的事,而是浏览器默认的双击缩放机制在作祟;touch-action 是唯一能从根源上关闭它、让 click 事件几乎零延迟的原生方案。
为什么 touch-action 能消除 300ms 延迟
浏览器为支持双击缩放(double-tap to zoom),会在触摸结束(touchend)后等待约 300ms,确认用户是否要发起第二次点击。这个等待期阻塞了 click 事件触发。
touch-action 告诉浏览器:“这个区域不支持缩放、平移等多点手势”,从而跳过等待逻辑,click 立即触发。
- 设为
touch-action: manipulation是最常用且安全的选择:禁用缩放与双指拖拽,但保留单指滚动和点击 - 设为
touch-action: none会彻底禁用所有原生手势(包括滚动),慎用 - 设为
touch-action: auto(默认值)即恢复 300ms 延迟,等于没设
哪些元素必须加 touch-action: manipulation
所有具备点击交互意图的非表单控件,尤其是那些你用 click 或 tap 监听的容器:
- 自定义按钮(
<div class="btn">、<code><span onclick="..."></span>) - 卡片式列表项(
<article onclick="..."></article>) - Tab 标签页切换区、轮播图指示点
- React/Vue 中用
@click或onClick绑定的 wrapper 元素 - 滚动卡顿或完全失效(尤其在 iOS Safari)
- 部分安卓 WebView 下点击无响应
- Chrome DevTools 提示
Unable to preventDefault inside passive event listener - 删掉不必要的
preventDefault()(90% 场景其实不需要) - 显式设置
touch-action: none或manipulation,再配合{ passive: false }添加监听器
注意:<button></button>、<a href></a>、<input type="button"> 等原生可点击元素默认已启用优化,无需额外设置 —— 但如果你重置了它们的 display 或覆盖了 touch-action,就得手动补回。
touch-action 和 preventDefault 的冲突点
如果同时在 touchstart 中调用 event.preventDefault(),且未正确设置 touch-action,会导致:
根本原因是:未声明 touch-action 时,浏览器将 touchstart 视为「被动监听」(passive),禁止调用 preventDefault()。解决方案只有两个:
兼容性与兜底写法
touch-action 在 iOS 9.3+、Android Chrome 36+、Firefox 52+ 均稳定支持;IE10+ 支持但语法略有差异(-ms-touch-action)。
推荐生产环境写法:
.btn, .card, [data-role="tab"] {
touch-action: manipulation;
-ms-touch-action: manipulation;
}
不要只靠 JS 检测 UA 或加 polyfill —— 这是纯 CSS 行为,无运行时成本,也不依赖框架。漏掉一个 touch-action,就可能让某个按钮在 iPhone 上始终慢半拍,而这个问题在线上很难被复现和定位。











