移动端300ms点击延迟是为识别双击缩放预留的判断窗口,并非bug;touch-action: manipulation可消除该延迟,但仅对可点击元素生效且需现代浏览器支持。
这不是bug,是浏览器为识别双击缩放(double-tap to zoom)预留的判断窗口。iOS Safari 和早期 Android 浏览器默认启用,哪怕页面没开缩放,这个延迟也照常存在。
触发条件很常见:用户单击一个 <button>、带 onclick 的 <div>,或用 addEventListener('click', ...) 绑定的元素——只要没明确告诉浏览器“这里不需要双击”,就会等满约300ms才派发 click 事件。
能,但只对「可点击区域」生效,且有明确限制:
touch-action: manipulation 等价于 pan-x pan-y pinch-zoom,它允许滚动和缩放,但禁止了 double-tap-zoom 和 long-press 触发菜单,从而跳过300ms等待click 或有 onclick 的元素,对纯 touchstart 监听无效body 上——如果页面需要双指缩放图表或长按复制文字,会直接禁用这些能力推荐写法:
.btn, .nav-link, [role="button"] { touch-action: manipulation; }
立即学习“前端免费学习笔记(深入)”;
touch-action: none 会把所有原生触摸行为都接管掉,包括滚动、缩放、点击判定。此时浏览器彻底放弃自动处理,click 事件压根不会触发,必须手动监听 touchstart/touchend 并自己模拟点击逻辑。
常见错误场景:
<div class="carousel"> 加了 touch-action: none,结果内部按钮点不动了preventDefault() 或节流,导致 touchmove 阻塞主线程,滑动卡顿touch-action,仍要靠 fastclick 或 pointer-events: none + touchstart 模拟现在基本不用了。现代框架(Vue/React)默认生成的按钮、带 role="button" 的元素,配合 touch-action: manipulation 就足够。fastclick 的副作用很明显:
hammer.js)冲突,可能吞掉 touchend
chrome://flags/#enable-fast-clicks 后,fastclick 反而引入冗余判断真要兼容老设备(比如 Android 4.3 WebView),优先加这行 CSS:
* { touch-action: manipulation; }再补一句 document.addEventListener('touchstart', function() {}, { passive: true }); 防止被强制同步阻止滚动。最易被忽略的一点:CSS 的 touch-action 不会继承,子元素必须显式设置,或者用属性选择器批量覆盖。写成 button { touch-action: manipulation; } 比 body { touch-action: manipulation; } 安全得多。