移动端300ms延迟问题和点击穿透问题

2022-11-19,,,

一、移动端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带来的卡顿慢慢变得让人难以接受。

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

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

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

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

 <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
方案2:FastClick

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

<script src="https://cdn.bootcdn.net/ajax/libs/fastclick/1.0.6/fastclick.js"></script>
<script>
    if('addEventListener' in document) {
        document.addEventListener('DOMContentLoaded', function(){
            FastClick.attach(document.body) // click 事件被代理
        }, false)
    }
</script>

二、点击穿透问题:

说完移动端点击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元素是一个链接,那此时页面就会意外地跳转。

解决问题见:方法汇集

移动端300ms延迟问题和点击穿透问题的相关教程结束。

《移动端300ms延迟问题和点击穿透问题.doc》

下载本文的Word格式文档,以方便收藏与打印。