300 毫秒点击延迟的来龙去脉 以及临时的解决方案

300 毫秒点击延迟的来龙去脉

凌征

原文地址:What Exactly Is..... The 300ms Click Delay

快速响应是所有 UI 实现的重中之重。研究表明,当延迟超过 100 毫秒,用户就能感受到界面的卡顿。 然而,出于对手指触摸滑动的区分,移动端页面对于触摸事件会有 300 毫秒的延迟,导致多数用户感觉移动设备上基于 HTML 的 web 应用界面响应速度慢。 本文主要讨论上述延时的来历,浏览器生产商的考虑,以及我们作为开发者,当前应该如何处理这个问题。

300 毫秒延迟的来历

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

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

双击缩放

双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。

下面以这篇网站响应时间的文章页面为例,刚一打开页面,除了文章本身,我们还看到顶部通栏、菜单等非关键性要素。

我们进入这个页面的目的显然是为了阅读这篇文章。所以当我们双击屏幕时,Safari 会相当智能地缩放至主体文章。

上述例子表明,iOS Safari 在双击后准确地定位到页面主体文章,并将其缩放至适合比例展现。这也相当符合个人使用习惯。

那么这和 300 毫秒延迟有什么联系呢?

假定这么一个场景。用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。

于是,300 毫秒延迟就这么诞生了。

后 iPhone 时代的 300 毫秒延迟

鉴于 iPhone 的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放。几乎现在所有的移动端浏览器都有这个功能。 六年前,一个人们还在为通过移动设备上网而惊叹的时期,如此性能损失并无大碍。然而如今,是个移动端开发的 web 应用性能可以同原生应用匹敌的时代,所有的单击事件都有 300 毫秒延迟,必然是不可接受的。此外,随着响应式设计的逐步推进,开发者们已经根据设备本身的尺寸对站点进行了优化,也就逐渐淘汰了诸如双击缩放的约定。

可喜的是,浏览器开发商已经意识到这个问题,并已相继提出了一些解决方案。

注:iOS Safari 还有一个鲜为人知的约定。用户可以在靠近屏幕顶部或底部约 1/4 范围内的区域双击来滚动页面内容。当你在一个放大了的页面内竖向滚动的时候,是否有过不小心将页面横向滚动的经历?双击滚动正是为解决这个问题而生的。尽管后续出现的移动端浏览器复制了双击缩放这一行为,它们并未复制双击滚动的行为。这是我们稍后将会讨论到的很重要的一点。

浏览器开发商提供的解决方案

避免点击延迟,提供一个响应迅速的移动端浏览器,可以说这是浏览器开发商的当务之急(当然,苹果公司除外)。因此,开发商们提供了一些比较有意思的解决方案。

禁用缩放

首先来看一个一目了然的解决方案。既然双击缩放仅对那些可被缩放的页面来说有存在意义,那对于不可缩放的页面,直接去掉点击延迟,何乐而不为呢?这里所说的不可缩放,是指使用了下述 <meta> 标签的页面。

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

Android 平台的 Chrome 浏览器率先做出了这一改变,Android 平台的 Firefox 浏览器随后实践之。其他浏览器开发商对这点优化暂无明确计划。

然而这个解决方案看似完美,但也带来一个明显的缺陷 —— 你必须完全禁用缩放来达到目的,而从移动端站点的可用性和可访问性来看,缩放是相当关键的一环。你很可能已经遇到过这个问题,即你想要放大一张图片或者一段字体较小的文本,却发现无法完成操作。

只能说 Android 平台上的 Chrome 和 Firefox 浏览器提供的禁用缩放优化,仅适用于 web 游戏等某些特定的场景,但多数网站并不能从中获益。

不过,Google Chrome 开发团队最近提出了更好的方式。

width=device-width Meta 标签

除了双击缩放的约定外,iPhone 诞生时就有的另一个约定是,在渲染桌面端站点的时候,使用 980 像素的视口宽度,而非设备本身的宽度(iPhone 是 320 像素宽)。

下面是一个非常简单的页面,展现一张小猫的照片,照片宽为 320 像素。

<!doctype html>
<html>
    <head><title>Kitty!</title></head>
    <body>
        <img src="http://placekitten.com/320/320">
    </body>
</html>

由于默认的视口宽度是 980 像素,在 iPhone 上会看到我们的小猫蜷缩在了左上角。

当然,我们可以继续用 <meta> 标签来进行配置。

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

这条代码告诉浏览器将视口大小设为设备本身的尺寸。这在 iPhone 上的效果就是把视口宽度从默认的 980 像素改为 320 像素。下面的截图,即为添加这条代码之后的效果,现在这张照片就撑满整个屏幕宽度了。

注:上述默认视口尺寸的约定,也被后续其他浏览器开发商所复制。因此上述现象不止是针对 iPhone 和 iOS Safari 浏览器。

那这一约定又和 300 毫秒点击延迟有什么联系呢?

Chrome 开发团队不久前宣布,在 Chrome 32 这一版中,他们将在包含 width=device-width 或者置为比 viewport 值更小的页面上禁用双击缩放。当然,没有双击缩放就没有 300 毫秒点击延迟。

深入之后,我们会发现这一做法还是相当有道理的。在我们还不知道响应式设计为何物的时代,双击缩放的诞生解决了在移动设备上浏览桌面端站点的问题。既然站点内包含了 width=device-width 这一<meta> 标签,也就意味着这个网站采用了响应式设计,因此也就消除了在该站点上可能潜在的双击缩放需求。

这一解决方案的另一个关键之处在于它只是去除了双击缩放,但用户仍可以使用双指缩放 (pinch to zoom)。可见,缩放功能并非被完全禁用,也就不存在可用性和可访问性的问题了。

在我看来,这是一个令人振奋的方案,很好地提升了移动端站点的性能。当然,主要的问题是width=device-width 这一优化目前仅被 Chrome 32 所支持。

那么其他浏览器是否也会实现这一优化?它所带来的性能提升显而易见,Firefox 很有可能会随后跟上。至于 Internet Explorer,除非其开发团队只看好指针事件 (pointer events,即将在下一节介绍)。这里最举棋不定的还属 iOS。

除了双击缩放,前面还提到 iOS Safari 是唯一一个提供双击滚动的移动端浏览器。如果 iOS 要实现上述优化,那势必要去掉双击滚动。结果如何,还留待时间为我们解答。

以上就是使用 <meta> 标签配置视口信息来解决 300 毫秒点击延迟的全部内容了,但别急,还有一个值得讨论的方案 —— 指针事件。

指针事件 (Pointer Events)

指针事件最初由微软提出,现已进入 W3C 规范的候选推荐标准阶段 (Candidate Recommendation)。指针事件是一个新的 web 事件系列,相应的规范旨在使用一个单独的事件模型,对所有输入类型,包括鼠标 (mouse)、触摸 (touch)、触控 (stylus) 等,进行统一的处理。

例如,你可以只去监听一个元素的 pointerdown 事件,无需分别监听其 touchstart 和mousedown 事件。对指针事件的深入解析已经超出了本文的讨论范围,但有一个和点击延迟直接相关的实现 —— 一个名为 touch-action 的新 CSS 属性。

根据规范touch-action 属性决定 “是否触摸操作会触发用户代理的默认行为。这包括但不限于双指缩放等行为”

从实际应用的角度来看,touch-action 决定了用户在点击了目标元素之后,是否能够进行双指缩放或者双击缩放。因此,这也相当完美地解决了 300 毫秒点击延迟的问题。

touch-action 的默认值为 auto,将其置为 none 即可移除目标元素的 300 毫秒延迟。例如,下面的代码在 IE10 和 IE11 上移除了所有链接和按钮元素的点击延迟。

a[href], button {
    -ms-touch-action: none; /* IE10 */
    touch-action: none;     /* IE11 */
}

你甚至可以在 <body> 元素上设置 touch-action: none,这就彻底禁用了双击缩放 (注:这也同时禁用了双指缩放,因此也会带来前面讨论到的可访问性和可用性问题。)

但就目前而言,只有 Internet Explorer 实现了指针事件,不过近期 Chrome 也宣布了将在未来的版本中提供支持

好消息是,我们现在已经有一些指针事件的 polyfills 可以在项目中使用了。接下来我们将讨论当下可用的 polyfill 以及其他解决 300 毫秒延迟的方案。

当前如何避免延迟

尽管浏览器开发商针对 300 毫秒延迟问题提出了一些解决方案,但目前并没有简单通用的方案。不过,已经有好多开发者考虑过这一问题,并带来了一些基于 JavaScript 的跨平台解决方案。这些方案可以归为两类 —— 针对指针事件的 polyfill 和“快速点击 (fast click)”。

首先来说说指针事件的 polyfill。

指针事件的 polyfill

指针事件的 polyfill 比较多,以下列出比较流行的几个。

为避免 300 毫秒点击延迟,我们主要关心这些 polyfill 是如何在非 IE 浏览器中模拟 CSS touch-action 属性的,这其实是一个不小的挑战。由于浏览器会忽略不被支持的 CSS 属性,唯一能够检测开发者是否声明了 touch-action: none 的方法是使用 JavaScript 去请求并解析所有的样式表。HandJS 也正是这么做的,但不管是从性能上来看还是其他一些复杂的方面,这都会遇到问题。

Polymer 则是通过判断标签上的 touch-action 属性 (attribute),而非 CSS 代码。下面的代码展示了 Polymer 是如何在链接上模拟 CSS touch-action: none 属性的。

<a href="http://google.com" touch-action="none">Google</a>

这对于我们开发者来说意味着什么?如果你比较感兴趣,想深入指针事件,那上述 polyfill 就非常适合应用到手头的项目中。然而,你若只想寻求一个解决 300 毫秒点击延迟的方法,上述方案可能就有点过了,因为它们要么是资源密集型的方案,要么是 touch-action 属性的非标准化模拟。所以,接下去我们要来看一些专门针对 300 毫秒延迟而生的解决方案。

注:上面这一节内容大多参考自 Points 这个 Polyfill 的 README 文件。感兴趣的话不妨深入阅读之。

FastClick

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

FastClick 的使用方法非常简单,在 window load 事件之后,在 <body> 上调用FastClick.attach() 即可。

window.addEventListener( "load", function() {
    FastClick.attach( document.body );
}, false );

attach() 方法虽可在更具体的元素上调用,直接绑定到 <body> 上可以确保整个应用都能受益。当 FastClick 检测到当前页面使用了基于 <meta> 标签或者 touch-action 属性的解决方案时,会静默退出。可以说,这是真正的跨平台方案出来之前一种很好的变通方案。

就目前而言,FastClick 非常实际地解决 300 毫秒点击延迟的问题。唯一的缺点可能也就是该脚本的文件尺寸 (尽管它只有 10kb)。如果你非常在意这点文件大小,可以尝试一下 Filament Group 的 Tappy!,或者 tap.js。两者都相当轻量,能够通过监听 tap 而非 click 事件来绕过 300 毫秒延迟。

Kendo UI Mobile

最后一点,如果你是 Kendo UI Mobile 的用户,那你完全不必担心上述问题。一个自定义的点击延迟解决方案已经作为 Touch widget 的一部分打包好了。这个 touch widget 是一个跨平台的 API,帮助处理所有平台的用户点击事件,所有的 Kendo UI Mobile 组件都会默认调用它。

实际上,这也是为什么在 HTML5 Mobile Challenge 中,我们制作的这个名为 cuteness 的应用,很难分辨出它到底是一个 web 应用还是原生应用。如果你是第一次听说,现在就可以在手机上打开 cuteness.io来体验一下。

小结

尽管苹果公司创造的双击缩放行为,是一种在移动设备上访问桌面端站点的不错的解决方案,但随之引入的 300 毫秒点击延迟也成为了移动端网站让用户感觉卡顿的罪魁祸首之一。

与此同时,浏览器开发商也提出了一些解决方案。对于缩放被禁用的网站,Android 平台上的 Chrome 和 Firefox 浏览器会禁用双击缩放功能;如果站点内配置了内容为 width=device-width 的 <meta>标签,Chrome 32 及以上版本的浏览器也会禁用双击缩放功能;Internet Explorer 则对元素引入了全新的 CSS 属性,touch-action,若将其置为 none,也会取消该元素上的点击延迟。

由于这些解决方案较为零碎,社区里也有一些基于 JavaScript 的解决方案,包括一些指针事件的 polyfill,诸如 FastClick 之类专门为这个问题而生的脚本,以及类似 Kendo UI Mobile 等自主方案。

虽然 JavaScript 的方案很好地解决了延迟问题,但毕竟只是临时的措施。浏览器本身所提供的方案,例如 Chrome 的 width=device-width 优化以及 Internet Explorer 的指针事件等,更属长久之计。

未来发展如何,让我们拭目以待。

学习来源:http://thx.github.io/mobile/300ms-click-delay/

时间: 2024-10-12 18:11:59

300 毫秒点击延迟的来龙去脉 以及临时的解决方案的相关文章

移动端Click300毫秒点击延迟的来龙去脉(转)

原文地址:What Exactly Is….. The 300ms Click Delay 快速响应是所有 UI 实现的重中之重.研究表明,当延迟超过 100 毫秒,用户就能感受到界面的卡顿. 然而,出于对手指触摸滑动的区分,移动端页面对于触摸事件会有 300 毫秒的延迟,导致多数用户感觉移动设备上基于 HTML 的 web 应用界面响应速度慢. 本文主要讨论上述延时的来历,浏览器生产商的考虑,以及我们作为开发者,当前应该如何处理这个问题. 300 毫秒延迟的来历 这要追溯至 2007 年初.苹

移动端300毫秒事件响应延迟解决方法[fastclick]

vue-cli[2.x]中: 安装 npm install fastclick --save 使用: 在main.js中 :先 import fastClick from 'fastclick' 然后 fastClick.attach(document.body) import Vue from 'vue' import App from './App' import router from './router' import fastClick from 'fastclick' import

移动端300ms的点击延迟以及解决方案

[今天做在移动端的一些效果时,我选择使用动画而不是用过渡,这个300ms的点击延迟是我为什么使用动画而不使用过渡最主要的一个原因] 动画和过渡 共同点:都是css控制DOM运动, 不同点: 1.过渡:只有两个关键帧,开始和结束: 2.动画可以设置多个关键帧 3.过渡必须通过事件去触发 4.动画不需要打开即可运动 [CSS执行速度更快,js事件触发执行,手机端点击类事件则会遇上300ms点击延迟,用户体验更差] 一.移动端300ms点击延迟 一般情况下,如果没有经过特殊处理,移动端浏览器在派发点击

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

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

移动端触屏click点击事件延迟问题,以及tap的解决方案

在移动端 触屏click事件虽然也会响应,但是总感觉是有延迟,一直听说click事件在手机上有200~300毫秒的延迟问题,亲自测了一下,在pc端模拟手机的话是测不出来的,但是用手机测试时发现延迟非常明显,用我的iphone5执行下段测试代码,平均延迟在370毫秒!结果非常惊人,所以在移动端必须得用tap事件了,click不仅仅是慢的问题,而且会严重影响css3动画!没错,这绝对是真的,我做的单页应用,用click事件执行的,点击后css3切换动画,经常会出现动画被省略掉直接到最后一个keyfr

分享一个移动项目中消除click事件点击延迟的方法

对于前端工程师来说,apicloud无疑给我们提供了很好的平台,有各种各样的模块供我们使用,但是在实际项目的时候,很大部分的代码,还是需要我们用html css js来实现的.但是呢,移动端页面对于click事件会有 300 毫秒的延迟,导致多数用户感觉移动设备上基于 HTML 的 web 应用界面响应速度慢. 在这里推荐一个简单易用的 js库,用来消除界面中的click事件造成的延迟. https://github.com/ftlabs/fastclick 目前,亲测在iphone表现很完美.

移动浏览器Chrome 32 for Android去掉了300ms点击延迟

翻译一篇关于移动浏览器300ms延迟的有用文章,原文地址  http://updates.html5rocks.com/2013/12/300ms-tap-delay-gone-away 去掉移动设备浏览器上的300ms点击延迟 你可以在网站上找到很多关于在为了快速流畅的网站用户体验,在某个地方减少10ms或90ms的文章.不幸的是,在基于触屏的跨平台移动浏览器上,触碰或点击一个物体时有一个人为的300ms延迟,即300ms后浏览器才认为是一个点击事件.当人们认为移动Web应用比原生应用慢时,这

fastclick:处理移动端click事件300毫秒延迟

1.兼容性 iOS 3及更高版本的移动Safari iOS 5及更高版本的Chrome Android上的Chrome(ICS) Opera Mobile 11.5及以上版本 Android 2以来的Android浏览器 PlayBook OS 1及以上版本 2.不应用FastClick的场景 桌面浏览器; 如果视口元标签中设置了width=device-width,Android上的Chrome 32+会禁用300ms延时; <meta name="viewport" cont

vue 解决300毫秒延迟

解决方案: (1)设置不能缩放:user-scalable=no 不能缩放就不会有双击缩放操作,因此click事件也就没了300ms延迟,这个是Chrome首先在Android中提出的 (2)设置显示宽度:width=device-width Chrome 开发团队在 Chrome 32 这一版中,他们将在包含 width=device-width 或者比 viewport 值更小的页面上禁用双击缩放. (3)IE的指针事件 (Pointer Events):touch-action:none