通常状况下,若是没有通过特殊处理,移动端浏览器在派发点击事件的时候,一般会出现300ms左右的延迟。也就是说,当咱们点击页面的时候移动端浏览器并非当即做出反应,而是会等上一小会儿才会出现点击的效果。在移动WEB兴起的初期,用户对300ms的延迟感受不明显。可是,随着用户对交互体验的要求愈来愈高,现今,移动端300ms的点击延迟逐渐变得明显而没法忍受。html
那么,移动端300ms的点击延迟是怎么来的呢?git
问题由来
这要追溯至 2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的。因而苹果的工程师们作了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。github
这当中最出名的,当属双击缩放(double tap to zoom),这也是会有上述 300 毫秒延迟的主要缘由。web
双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。 那么这和 300 毫秒延迟有什么联系呢? 假定这么一个场景。用户在 iOS Safari 里边点击了一个连接。因为用户能够进行双击缩放或者双击滚动的操做,当用户一次点击屏幕以后,浏览器并不能马上判断用户是确实要打开这个连接,仍是想要进行双击操做。所以,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。 鉴于iPhone的成功,其余移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎如今全部的移动端浏览器都有这个功能。以前人们刚刚接触移动端的页面,在欣喜的时候每每不会care这个300ms的延时问题,但是现在touch端界面如雨后春笋,用户对体验的要求也更高,这300ms带来的卡顿慢慢变得让人难以接受。浏览器
也就是说,移动端浏览器会有一些默认的行为,好比双击缩放、双击滚动。这些行为,尤为是双击缩放,主要是为桌面网站在移动端的浏览体验设计的。而在用户对页面进行操做的时候,移动端浏览器会优先判断用户是否要触发默认的行为。app
那有什么办法能够解决这个问题呢?webapp
浏览器开发商要对移动端浏览器自己的设计进行改善,以提供长远的解决方案。函数
目前,浏览器开发商的解决方案主要有一下三种方案:
方案一:禁用缩放
当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是支持的,可是其余浏览器支持不完善。具体请看这篇文章:移动端Click300毫秒点击延迟的前因后果(转)。
因此,在浏览器开发商最终统一的解决方案出来以前,咱们还有一些基于Javascript的现成的解决方案能够用。
方案一:指针事件的polyfill
如今除了IE,其余大部分浏览器都还不支持指针事件。有一些JS库,可让咱们提早使用指针事件,好比
然而,咱们如今关心的不是指针事件,而是与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元素是一个连接,那此时页面就会意外地跳转。
移动端Click300毫秒点击延迟的前因后果(转)
移动端click事件延迟300ms究竟是怎么回事,该如何解决?
详细解析-移动H5点击穿透现象