如何解决移动端点击延迟300ms问题

目录
文章目录隐藏
  1. 一、移动端 300ms 点击延迟
  2. 浏览器开发商的解决方案
  3. 「真正解决方案」

最近在做项目的过程中,发现了一个由来已久的传说,300ms 延迟问题,可能很多同学没听过,也可能遇到过但不知道怎描述。这个问题导致了很多体验性 BUG,让前端背锅,所以今天我就曝光出来,以免大家以后遇到心中有数。

如何解决移动端点击延迟 300ms 问题

一、移动端 300ms 点击延迟

一般情况下,如果没有经过特殊处理,移动端浏览器在派发点击事件的时候,通常会出现 300ms 左右的延迟。也就是说,当我们点击页面的时候移动端浏览器并不是立即作出反应,而是会等上一小会儿才会出现点击的效果。在移动 WEB 兴起的初期,用户对 300ms 的延迟感觉不明显。但是,随着用户对交互体验的要求越来越高,现今,移动端 300ms 的点击延迟逐渐变得明显而无法忍受。

那么,移动端 300ms 的点击延迟是怎么来的呢?

问题由来

这要追溯至 2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。

这当中最出名的,当属双击缩放(double tap to zoom),这也是会有上述 300 毫秒延迟的主要原因。

双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。那么这和 300 毫秒延迟有什么联系呢?假定这么一个场景。用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。鉴于 iPhone 的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎现在所有的移动端浏览器都有这个功能。之前人们刚刚接触移动端的页面,在欣喜的时候往往不会 care 这个 300ms 的延时问题,可是如今 touch 端界面如雨后春笋,用户对体验的要求也更高,这 300ms 带来的卡顿慢慢变得让人难以接受。

也就是说,移动端浏览器会有一些默认的行为,比如双击缩放、双击滚动。这些行为,尤其是双击缩放,主要是为桌面网站在移动端的浏览体验设计的。而在用户对页面进行操作的时候,移动端浏览器会优先判断用户是否要触发默认的行为。

那有什么办法可以解决这个问题呢?

浏览器开发商的解决方案

浏览器开发商要对移动端浏览器本身的设计进行改善,以提供长远的解决方案。

目前,浏览器开发商的解决方案主要有一下三种方案:

方案一:禁用缩放

当 HTML 文档头部包含如下 meta 标签时:

<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">

表明这个页面是不可缩放的,那双击缩放的功能就没有意义了,此时浏览器可以禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。

这个方案有一个缺点,就是必须通过完全禁用缩放来达到去掉点击延迟的目的,然而完全禁用缩放并不是我们的初衷,我们只是想禁掉默认的双击缩放行为,这样就不用等待 300ms 来判断当前操作是否是双击。但是通常情况下,我们还是希望页面能通过双指缩放来进行缩放操作,比如放大一张图片,放大一段很小的文字。

方案二:更改默认的视口宽度

一开始,为了让桌面站点能在移动端浏览器正常显示,移动端浏览器默认的视口宽度并不等于设备浏览器视窗宽度,而是要比设备浏览器视窗宽度大,通常是 980px。我们可以通过以下标签来设置视口宽度为设备宽度。

<meta name="viewport" content="width=device-width">

因为双击缩放主要是用来改善桌面站点在移动端浏览体验的,而随着响应式设计的普及,很多站点都已经对移动端坐过适配和优化了,这个时候就不需要双击缩放了,如果能够识别出一个网站是响应式的网站,那么移动端浏览器就可以自动禁掉默认的双击缩放行为并且去掉 300ms 的点击延迟。如果设置了上述 meta 标签,那浏览器就可以认为该网站已经对移动端做过了适配和优化,就无需双击缩放操作了。

这个方案相比方案一的好处在于,它没有完全禁用缩放,而只是禁用了浏览器默认的双击缩放行为,但用户仍然可以通过双指缩放操作来缩放页面。

方案三:CSS touch-action

网上很多文章把这个方案归结为指针事件,这令我很疑惑。

以我的理解来看,指针事件的提出并不是为了解决 300ms 点击延迟的,而是为了使用一个单独的事件模型,对鼠标、触摸、触控等多种输入类型进行统一的处理。也就是说,移动浏览器不用再为不同的输入设备设计不同的事件,网页的开发者也不用再为不同输入类型的设备写不同的事件响应代码,而是通过统一的指针事件就可以开发出跨不同输入类型终端的应用。

跟 300ms 点击延迟相关的,是 touch-action 这个 CSS 属性。这个属性指定了相应元素上能够触发的用户代理(也就是浏览器)的默认行为。如果将该属性值设置为 touch-action:none,那么表示在该元素上的操作不会触发用户代理的任何默认行为,就无需进行 300ms 的延迟判断。

而设置这个 CSS 属性与否,指针事件应该都是可以工作的。所以,网上的文章令我很疑惑,现有的解决方案

「真正解决方案」

要解决 300ms 点击延迟的问题,从长远来说,自然还是得浏览器开发商提供统一的最终的解决方案。但是,到目前为止,以上三种方案并不能提供很好的兼容性,对于方案一和方案二,Chrome 是率先支持的,Firefox 紧随其后,然而令 Safari 头疼的是,它除了双击缩放还有双击滚动操作,如果采用这种两种方案,那势必连双击滚动也要一起禁用;对于方案三,IE 是支持的,但是其他浏览器支持不完善。

所以,在浏览器开发商最终统一的解决方案出来之前,我们还有一些基于 Javascript 的现成的解决方案可以用。

方案一:指针事件的 polyfill

现在除了 IE,其他大部分浏览器都还不支持指针事件。有一些 JS 库,可以让我们提前使用指针事件,比如:

  • Google 的 Polymer
  • 微软的 HandJS
  • Rich-Harris 的 Points

然而,我们现在关心的不是指针事件,而是与 300ms 延迟相关的 CSS 属性 touch-action。由于除了 IE 之外的大部分浏览器都不支持这个新的 CSS 属性,所以这些指针事件的 polyfill 必须通过某种方式去模拟支持这个属性。一种方案是 JS 去请求解析所有的样式表,另一种方案是将 touch-action 作为 html 标签的属性。

方案二:FastClick

FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。FastClick 的实现原理是在检测到 touchend 事件的时候,会通过 DOM 自定义事件立即出发模拟一个 click 事件,并把浏览器在 300ms 之后的 click 事件阻止掉。

二、点击穿透问题

说完移动端点击 300ms 延迟的问题,还不得不提一下移动端点击穿透的问题。可能有人会想,既然 click 点击有 300ms 的延迟,那对于触摸屏,我们直接监听 touchstart 事件不就好了吗?

使用 touchstart 去代替 click 事件有两个不好的地方。

第一:touchstart 是手指触摸屏幕就触发,有时候用户只是想滑动屏幕,却触发了 touchstart 事件,这不是我们想要的结果;

第二:使用 touchstart 事件在某些场景下可能会出现点击穿透的现象。

什么是点击穿透?

假如页面上有两个元素 A 和 B。B 元素在 A 元素之上。我们在 B 元素的 touchstart 事件上注册了一个回调函数,该回调函数的作用是隐藏 B 元素。我们发现,当我们点击 B 元素,B 元素被隐藏了,随后,A 元素触发了 click 事件。

这是因为在移动端浏览器,事件执行的顺序是 touchstart>touchend>click。而 click 事件有 300ms 的延迟,当 touchstart 事件把 B 元素隐藏之后,隔了 300ms,浏览器触发了 click 事件,但是此时 B 元素不见了,所以该事件被派发到了 A 元素身上。如果 A 元素是一个链接,那此时页面就会意外地跳转。

最典型的问题是弹出框 B 要滑动的时候,底下的 A 也跟着滑动,令人头疼,那么怎么解决呢?这个问题留给大家,大家也可以在下方留言讨论。

「点点赞赏,手留余香」

21

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 如何解决移动端点击延迟300ms问题

2 评论

发表回复