移动端300ms点击延迟
由来
2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。
这当中最出名的,当属双击缩放(double tap to zoom),这也是会有上述 300 毫秒延迟的主要原因。
双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。 那么这和 300 毫秒延迟有什么联系呢? 假定这么一个场景。用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。 鉴于iPhone的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎现在所有的移动端浏览器都有这个功能。之前人们刚刚接触移动端的页面,在欣喜的时候往往不会care这个300ms的延时问题,可是如今touch端界面如雨后春笋,用户对体验的要求也更高,这300ms带来的卡顿慢慢变得让人难以接受。
也就是说,移动端浏览器会有一些默认的行为,比如双击缩放、双击滚动。这些行为,尤其是双击缩放,主要是为桌面网站在移动端的浏览体验设计的。而在用户对页面进行操作的时候,移动端浏览器会优先判断用户是否要触发默认的行为。重点:由于移动端会有双击缩放的这个操作,因此浏览器在click之后要等待300ms,看用户有没有下一次点击,也就是这次操作是不是双击。浏览器开发商的解决方案方案一:禁用缩放 当HTML文档头部包含如下meta标签时:
表明这个页面是不可缩放的,那双击缩放的功能就没有意义了,此时浏览器可以禁用默认的双击缩放行为并且去掉300ms的点击延迟。缺点:就是必须通过完全禁用缩放来达到去掉点击延迟的目的,然而完全禁用缩放并不是我们的初衷,我们只是想禁掉默认的双击缩放行为,这样就不用等待300ms来判断当前操作是否是双击。但是通常情况下,我们还是希望页面能通过双指缩放来进行缩放操作,比如放大一张图片,放大一段很小的文字。
点击穿透问题
现象:
点击穿透问题:点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件,蒙层的关闭按钮绑定的是touch事件,而按钮下面元素绑定的是click事件,touch事件触发之后,蒙层消失了,300ms后这个点的click事件fire,event的target自然就是按钮下面的元素,因为按钮跟蒙层一起消失了
跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转因为a标签跳转默认是click事件触发,所以原理和上面的完全相同
另一种跨页面点击穿透问题:这次没有mask了,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了和蒙层的道理一样,js控制页面跳转的逻辑如果是绑定在touch事件上的,而且新页面中对应位置的元素绑定的是click事件,而且页面在300ms内完成了跳转,三个条件同时满足,就出现这种情况了非要细分的话还有第四种,不过概率很低,就是新页面中对应位置元素恰好是a标签,然后就发生连续跳转了。。。诸如此类的,都是点击穿透问题
什么是点击穿透?
移动端浏览器, 事件执行顺序是 touchstart > touched > click. 而 click 事件有300ms 的延迟, 当 touchstart 事件把 b 元素隐藏之后, 隔了300ms, 浏览器触发了click事件,但是此时B元素不见了,所以该事件被派发到了A元素身上。如果A元素是一个链接,那此时页面就会意外地跳转。 事件 描述 触发时机 touchstart 开始触摸 手指接触屏幕时立即触发 touchmove 移动或拖拽 取决于系统和浏览器 touchend 触摸结束 手指理考屏幕时立即触发
解决方案:
只用 touch 把页面内所有的 click 全部换成 touch 事件('touchstart', 'touchend', 'tap'), 需要特别注意 a 标签, a 标签的 href 也是 click, 需要换成 js 控制跳转,或者直接用 span.
fastclick
在touchend事件上调用 preventDefault()在一次成功的点击后,建议接下来的 500ms 以内取消所有的 click 事件。分析点击事件,判断如果是慢速点击穿透,则取消所有 click 事件,如果是快速点击穿透,取消触摸事件 50ms以内的 click 事件即可。
最后更新于
这有帮助吗?