浏览器原理 · 36/51
1. addEventListener 第三个参数 2. addEventListener 与 attachEvent 区别 3. 浏览器兼容性测试与内核 4. 浏览器兼容性问题 5. 浏览器内核与引擎 6. 浏览器图层创建条件 7. 浏览器多进程架构 8. 浏览器渲染机制 9. 浏览器存储方案 10. 浏览器版本检测方法 11. children 与 childNodes 区别 12. 常见浏览器兼容性问题 13. Chrome 页面进程数量 14. 坐标系统对比 15. 多标签页通讯方案 16. 删除 Cookie 17. 自定义事件 18. DOM 事件处理方式演进 19. 元素尺寸属性对比 20. DOM 节点操作 21. DOM 事件机制 22. addEventListener 与 attachEvent 的区别 23. 获取页面所有复选框 24. HTMLCollection 与 NodeList 区别 25. Hybrid 应用开发 26. 强缓存命中机制 27. 浏览器缓存机制 28. 页面编码与资源编码不一致处理 29. jQuery 事件绑定方法对比 30. Input 点击触发的事件顺序 31. JavaScript 浏览器兼容性问题 32. jQuery 多事件绑定实现 33. JSBridge 原理 34. 链接点击后 Hover 失效解决方案 35. 减少重绘和回流的性能优化 36. 移动端 300ms 点击延迟问题 37. 移动端视口配置 38. 移动端点击穿透问题解决 39. 移动端兼容性问题 40. JSBridge 原理与实现 41. 移动端 1px 像素问题解决方案 42. 浏览器渲染流程 43. 页面加载完成事件对比 44. Offset、Scroll、Client 属性对比 45. 同源策略与跨域解决方案 46. Script 标签位置对页面加载的影响 47. Service Worker 与 PWA 48. 存储方案对比:Cookie、Storage、IndexedDB 49. 强缓存默认时间 50. URL 到页面显示的完整过程 51. V8 引擎 JavaScript 执行过程

移动端 300ms 点击延迟问题

移动端点击延迟的原因及解决方案

问题

移动端 H5 页面点击事件存在约 300ms 的延迟,导致用户体验不佳。为什么会有这个延迟?如何解决?

解答

延迟原因

早期移动浏览器为了判断用户是否在进行双击缩放操作,会在第一次点击后等待约 300ms:

  • 如果 300ms 内有第二次点击 → 触发双击缩放
  • 如果 300ms 内没有第二次点击 → 触发 click 事件

这个设计在智能手机早期是合理的,但随着响应式设计的普及,双击缩放的需求减少,300ms 延迟反而成了问题。

解决方案

1. 禁用缩放(推荐)

<!-- 禁用缩放后,浏览器会自动取消 300ms 延迟 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

2. 设置 viewport 宽度

<!-- Chrome 32+ 检测到 width=device-width 会自动禁用延迟 -->
<meta name="viewport" content="width=device-width">

3. CSS touch-action

/* 告诉浏览器该元素不需要默认的触摸行为 */
.no-delay {
  touch-action: manipulation;
}

/* 或者全局禁用 */
html {
  touch-action: manipulation;
}

4. FastClick(兼容老浏览器)

// 安装:npm install fastclick

import FastClick from 'fastclick';

// 在 DOM 加载完成后初始化
if ('addEventListener' in document) {
  document.addEventListener('DOMContentLoaded', function() {
    FastClick.attach(document.body);
  }, false);
}

5. 手动实现(简化版 FastClick 原理)

// FastClick 的核心思路:用 touchend 模拟 click
function fastClick(element, callback) {
  let startX, startY;
  
  element.addEventListener('touchstart', function(e) {
    // 记录触摸起始位置
    startX = e.touches[0].clientX;
    startY = e.touches[0].clientY;
  });
  
  element.addEventListener('touchend', function(e) {
    // 计算移动距离,判断是否为点击
    const endX = e.changedTouches[0].clientX;
    const endY = e.changedTouches[0].clientY;
    
    // 移动距离小于 10px 视为点击
    if (Math.abs(endX - startX) < 10 && Math.abs(endY - startY) < 10) {
      e.preventDefault(); // 阻止后续的 click 事件
      callback(e);
    }
  });
}

// 使用
fastClick(document.getElementById('btn'), function() {
  console.log('立即响应,无延迟');
});

现代浏览器的处理

现代移动浏览器已经优化了这个问题:

// 检测浏览器是否还有 300ms 延迟
function has300msDelay() {
  // 大多数现代浏览器在以下情况自动取消延迟:
  // 1. viewport 设置了 width=device-width
  // 2. 页面不可缩放
  // 3. 使用了 touch-action: manipulation
  
  const viewport = document.querySelector('meta[name="viewport"]');
  if (viewport) {
    const content = viewport.getAttribute('content');
    if (content.includes('width=device-width')) {
      return false; // 现代浏览器无延迟
    }
  }
  return true;
}

关键点

  • 原因:浏览器等待 300ms 判断是否双击缩放
  • 首选方案:设置 viewportwidth=device-widthtouch-action: manipulation
  • FastClick 原理:监听 touchend 事件,立即触发回调并阻止原生 click
  • 现代浏览器:Chrome 32+、iOS 9.3+ 等已自动优化,设置正确的 viewport 即可
  • 注意事项:FastClick 可能与某些第三方库冲突,现代项目优先用 CSS 方案