移动端 300 毫秒延迟,怎么解决?
移动端 300 毫秒延迟,指的是当没有经过特殊处理,移动端浏览器在派发点击事件的时候,通常会出现 300ms 左右的延迟。
为什么会有延迟?
1. 先说一下 300毫秒延迟的来历
这个就是当初,也就是 2007 年的时候,苹果公司在发布首款 iPhone 前夕,遇到一个问题 ,当时的网站都是为大屏幕设备所设计的,于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。
这当中最出名的,就当属于双击缩放。这也就是上述 300毫秒延迟的主要原因。
那么这和 300毫秒延迟有什么联系?
假设用户在浏览器中,点击一个链接。由于是用户可以进行双击或者缩放或者其他操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是要双击操作,因此浏览器就会等待 300 毫米,一判断用户是否再次点击了屏幕。于是这就是著名的 300 毫秒延迟。
2. 解决方案
2.1 禁止缩放
首先看一个很直接的解决方案,既然双击缩放仅对那些 可被缩放 的页面存在意义,那可以对不可缩放的页面,直接去掉点击延迟
<meta name="viewport" content="user-scalable=no"/>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">/
然而这个问题看似完美解决,但也带来了一个缺陷,就是必须完全禁止缩放来达到目的,但中移动端站点的可用性和可访问性来看,缩放是缩放是相当关键的一环。
2.2 width=device-width Meta 标签
除了双击缩放的预定外, iPhone 诞生时就有的另一个约定是, 在渲染桌面站点是时候,使用 980 像素的视口宽度,而非设备本身的宽度
当然,这个问题我们还可以用 <meta> 标签进行配置
<meta name="viewport" content="width=device-width"/>
这个代码就是告诉浏览器色将视口大小设为设备本身的尺寸。
因为双击缩放主要是来改善桌面站点在移动端浏览的体验,为随着响应式的普及,很多站点都已经对移动端做过适配和优化了,这就不需要双击缩放了, 既然站点内包含了 width=device-width 这个 <meta> 标签,也就意味着这个网站是响应式的网站,那么移动端浏览器就可以自动禁止掉双击缩放行为并且去掉 300ms 的点击延迟。
这个方案相对方案1 的好处在于,它没有完全禁止缩放,只是禁用了默认的双击缩放行为,但用户仍然可以通过双指缩放来缩放页面。
2.3 指针事件
指针事件最初是微软提出的。指针事件是一个新的 web 事件系列,对所有输入类型,包括 鼠标(mouse)、触摸(touch)、触控(stylus)等,进行统一处理。
也就是说浏览器不用再为不同的输入设备设计不同的事件,前端工程师也不用写不同的事件响应。而是通过统一的指针事件就可以开发不同的事件处理。一个名为 touch-action 的新 CSS 属性。
根据规范, touch-action 属性决定 “ 是否触摸操作会触发用户代理的默认行为。这包括但不限于双指缩放等行为”。
从实际应用的角度来看, touch-action 解决了用户在点击了目标元素之后,是否能够进行双指缩放后者双击缩放。因此,这也相当于完美地解决了 300 毫秒点击延迟的问题。
touch-action 默认值为 auto,将其设置 none 即可移除目标元素的 300 毫秒延迟。
3. 当前如何避免延迟
尽管浏览器开发商针对 300 毫秒延迟的问题提出了一些解决方案,当目前并没有简单通用的方案。不过好多的开发者考虑过这一问题,并带来了一些基于 JavaScript 的跨平台解决方案。这些方案可以归为两类 —— 指针事件的 polyfill 和 快速点击(fast click)。
3.1 指针事件的 polyfill
现在除了 IE,大部分浏览器还不支持指针事件,有一些 JS 库,可以让我们使用指针事件: 比如
- Google 的 Polymer
- 微软的 HandJS
- @RIch-Harris 的 Points
由于只有 IE 浏览器中可以使用 touch-action 属性,其他浏览器会被忽略,唯一能够检测开发者是否声明了 touch-action: none 的方法是使用 JavaScript 去请求解析所有的样式表。 HandJS 也是这么做的,当时不管从性能或者其他一些复杂方面,这都会遇到问题。
Polymer 则是通过判断标签上的 touch-action 属性, 而非 CSS 代码。
<a href="http://" touch-action="none"></a>
3.2 FastClick
FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级库。简单来说,FastClick 在检测到 touched 事件的时候,会通过 DOM 自定义事件立即出发一个模拟 click 事件,并把浏览器在 300 毫秒之后真正触发的 click 事件阻止掉。
FastClick 的使用方法,在 window.load 事件之后, 在 <body> 上调用 FastClick.attach()
window.addEventListener("load", ()=>{
FastClick.attach(document.body);
}, false )
并且当 FastClick 检测到当前页面使用了基于 <meta> 标签或者 touch-action 属性的解决方案时,会默默退出。