站点工具

用户工具


# 彻底弄清移动端300ms延时 ## 延时的由来 苹果发布IPhone时遇到一个问题——早期的网站都是针对PC设计的,手机屏幕尺寸很小,在手机端展示时页面内容的放大缩小是最常见的操作。所以IPhone规定,手指在屏幕快速双击时会放大或者缩小页面。如何判定手指是双击而不是单击两次呢?以两次敲击屏幕时间间隔是否超过约300ms来判定。

所谓的300ms延迟,指的是用户在点击屏幕之后(在touchend事件触发后),等待300~400ms才触发click事件。

举个例子,假设页面上有个链接,当用户点击链接时,浏览器无法立即判定用户是准备双击屏幕执行页面放大缩小,还是打算点击链接执行跳转。浏览器需要等待约300ms,如果300ms内有第二次点击,则认为是双击缩放页面。如果没有第二次点击才执行第一次点击的跳转。

在早起移动端发展还未起步的时候,用户能用手机上网已经很开心了不会挑剔300ms延迟,而现在这种延时带来的迟滞感对用户来说是无法忍受的。

## 与延时的战斗 #### 阶段1 苹果打开了移动端世界的大门,移动端safari带来了双击缩放和单击300ms延迟。其他移动端厂商抱苹果大腿,纷纷效仿。

#### 阶段2 谷歌意识到延迟是为了实现双击缩放,如果用户禁用了双击缩放浏览器就不需要再单击延迟。 ```html <meta name=“viewport” content=“user-scalable=no”> <meta name=“viewport” content=“initial-scale=1,maximum-scale=1”> ``` 所以对于早期的安卓和苹果浏览器,只要HTML加入上面代码禁止了页面缩放,对于用户的单击就不做延迟处理。

#### 阶段3 后来谷歌觉得为了不延迟而禁用页面缩放的操作有些太傻(双击缩放和双指缩放对手机用户来说是刚需),于是规定只要设置了移动端页面的特征meta就不再延迟,不需要禁用页面缩放。其他厂商和苹果也纷纷跟进。 ```html <meta name=“viewport” content=“width=device-width”> ``` 这样规定的思路是这样的:如果加了上面的meta,表示当前页面本来就是适合手机展示的页面(非PC排版在手机展示),缩放自然而然不是刚需,没必要为了缩放而加个延迟。

#### 阶段4 可能是苹果和谷歌觉得为了解决缩放搞这么复杂不值得,也可能是开发者乱加meta总是喜欢禁用页面缩放让厂商觉得违背了初衷。经过测试,发现IOS和安卓浏览器推翻了前面的约定,最新的浏览器上遵循下面的规律:

1. 页面总是能放大缩小。设置meta禁用页面缩放是无效的,比如即使页面加了<meta name=“viewport” content=“user-scalable=no”> 依然能双指缩放,双击还原。 1. 只要页面处于放大状态,单击就一定有延迟;只要页面处于未放大的原始状态,单击就一定没有延迟。在一般情况下,不管是pc端页面还是移动端页面,不管有没有设置meta,不管有没有禁用缩放,用户打开页面默认就处于原始状态,是没有延迟的。当用户双指放大后,单击才出现延迟。

浏览器厂商也提供了一种使用CSS来彻底取消延迟的方案。只要CSS里做了如下设置,不管页面是否处于放大状态,都会停止单击延迟。 ```css html {

touch-action: manipulation;

} ``` 经测试,双击页面依然会缩放,但单击链接会立即跳转。

## 旧版本浏览器处理 对于不同时期的移动端浏览器,取消单击延时有不同的写法。在处理时不仅需要考虑不同版本浏览器的兼容性,各自方案本身又有各自的缺点。如果需要兼容早期的浏览器,可以使用 [fastclick](https://github.com/ftlabs/fastclick) 这个库 。 ```css <script type='application/javascript' src='/path/to/fastclick.js'></Script> <script>

document.addEventListener('DOMContentLoaded', function() {
	FastClick.attach(document.body);
}, false); 

</Script> ``` 关于fastclick的原理,我们在下一篇文章讲解,并且会实现一个简化版的fastclick。

## 延迟的测试代码 分别开启以下代码中的注释,在IOS safari、安卓原生浏览器、UC浏览器上分别测试。 ```html <!DOCTYPE html> <head> <meta charset="utf-8">   <meta name="viewport" content="user-scalable=no"> <!-- <meta name="viewport" content="initial-scale=1,maximum-scale=1"> --> <!-- <meta name="viewport" content="width=device-width"> -->   <!-- <style> html { touch-action: manipulation; } </style> --> </head> <body> <div> <a id="link1" href="#1">链接#1</a> <a id="link2" href="#2">链接#2</a> </div> <div id="log"></div>   <script> const $ = s => document.querySelector(s) const log = str => $('#log').innerText = str let t   $('#link1').ontouchend = e => { t = Date.now() }   $('#link2').ontouchend = e => { t = Date.now() }   window.onhashchange = () => { log(`link: ${Date.now() - t}ms`) } </script> </body>



                        
                                            
若愚 · 2021/09/16 15:28 · 移动端_300ms.1631777330.txt.gz