天天看點

移動端300ms延遲的由來及解決方案

一、移動端300ms點選延遲的前因後果

一般情況下,如果沒有經過特殊處理,移動端浏覽器在派發點選事件的時候,通常會出現300ms左右的延遲。也就是說,當我們點選頁面的時候移動端浏覽器并不是立即作出反應,而是會等上300ms才會出現點選的效果。在移動WEB興起的初期,使用者對300ms的延遲感覺不明顯。但是,随着使用者對互動體驗的要求越來越高,目前移動端300ms的點選延遲逐漸變得明顯而無法忍受,那麼,移動端300ms的點選延遲是怎麼來的呢?

問題由來:

這要追溯至 2007 年初。蘋果公司在釋出首款 iPhone 前夕,遇到一個問題:當時的網站都是為大螢幕裝置所設計的。于是蘋果的工程師們做了一些約定,應對 iPhone 這種小螢幕浏覽桌面端站點的問題。這當中最出名的,當屬輕按兩下縮放(doubletap to zoom),這也是會有上述 300ms延遲的主要原因。

輕按兩下縮放,顧名思義,即用手指在螢幕上快速點選兩次,iOS 自帶的Safari 浏覽器會将網頁縮放至原始比例。那麼這和300ms延遲有什麼聯系呢? 假定這麼一個場景。使用者在 iOS Safari 裡邊點選了一個連結。由于使用者可以進行輕按兩下縮放或者輕按兩下滾動的操作,當使用者一次點選螢幕之後,浏覽器并不能立刻判斷使用者是确實要打開這個連結,還是想要進行輕按兩下操作。是以,iOS Safari 就等待 300 ms,以判斷使用者是否再次點選了螢幕。鑒于iPhone的成功,其他移動浏覽器都複制了 iPhone Safari 浏覽器的多數約定,包括輕按兩下縮放,幾乎現在所有的移動端浏覽器都有這個功能。之前人們剛剛接觸移動端的頁面,在欣喜的時候往往不會care這個300ms的延時問題,可是如今touch端界面如雨後春筍,使用者對體驗的要求也更高,這300ms帶來的卡頓慢慢變得讓人難以接受。

也就是說,移動端浏覽器會有一些預設的行為,比如輕按兩下縮放、輕按兩下滾動。這些行為,尤其是輕按兩下縮放,主要是為桌面網站在移動端的浏覽體驗設計的。而在使用者對頁面進行操作的時候,移動端浏覽器會優先判斷使用者是否要觸發預設的行為。

那有什麼辦法可以解決這個問題呢?

二、浏覽器開發商的解決方案

浏覽器開發商要對移動端浏覽器本身的設計進行改善,以提供長遠的解決方案。

目前,浏覽器開發商的解決方案主要有一下三種方案:

1、禁用縮放

當HTML文檔頭部包含如下meta标簽時:

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

表明這個頁面是不可縮放的,那輕按兩下縮放的功能就沒有意義了,此時浏覽器可以禁用預設的輕按兩下縮放行為并且去掉300ms的點選延遲。

這個方案有一個缺點,就是必須通過完全禁用縮放來達到去掉點選延遲的目的,然而完全禁用縮放并不是我們的初衷,我們隻是想禁掉預設的輕按兩下縮放行為,這樣就不用等待300ms來判斷目前操作是否是輕按兩下。但是通常情況下,我們還是希望頁面能通過雙指縮放來進行縮放操作,比如放大一張圖檔,放大一段很小的文字。

2、更改預設的視口寬度

一開始,為了讓桌面站點能在移動端浏覽器正常顯示,移動端浏覽器預設的視口寬度并不等于裝置浏覽器視窗寬度,而是要比裝置浏覽器視窗寬度大,通常是980px。我們可以通過以下标簽來設定視口寬度為裝置寬度。

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

因為輕按兩下縮放主要是用來改善桌面站點在移動端浏覽體驗的,而随着響應式設計的普及,很多站點都已經對移動端坐過适配和優化了,這個時候就不需要輕按兩下縮放了,如果能夠識别出一個網站是響應式的網站,那麼移動端浏覽器就可以自動禁掉預設的輕按兩下縮放行為并且去掉300ms的點選延遲。如果設定了上述

meta

标簽,那浏覽器就可以認為該網站已經對移動端做過了适配和優化,就無需輕按兩下縮放操作了。

這個方案相比方案一的好處在于,它沒有完全禁用縮放,而隻是禁用了浏覽器預設的輕按兩下縮放行為,但使用者仍然可以通過雙指縮放操作來縮放頁面。

3、CSStouch-action

以我的了解來看,指針事件的提出并不是為了解決300ms點選延遲的,而是為了使用一個單獨的事件模型,對滑鼠、觸摸、觸控等多種輸入類型進行統一的處理。也就是說,移動浏覽器不用再為不同的輸入裝置設計不同的事件,網頁的開發者也不用再為不同輸入類型的裝置寫不同的事件響應代碼,而是通過統一的指針事件就可以開發出跨不同輸入類型終端的應用。

跟300ms點選延遲相關的,是

touch-action

這個CSS屬性。這個屬性指定了相應元素上能夠觸發的使用者代理(也就是浏覽器)的預設行為。如果将該屬性值設定為

touch-action: none

,那麼表示在該元素上的操作不會觸發使用者代理的任何預設行為,就無需進行300ms的延遲判斷。

三、現有的解決方案

要解決300ms點選延遲的問題,從長遠來說,自然還是得浏覽器開發商提供統一的最終的解決方案。但是,到目前為止,以上三種方案并不能提供很好的相容性,對于方案一和方案二,Chrome是率先支援的,Firefox緊随其後,然而令Safari頭疼的是,它除了輕按兩下縮放還有輕按兩下滾動操作,如果采用這種兩種方案,那勢必連輕按兩下滾動也要一起禁用;對于方案三,IE是支援的,但是其他浏覽器支援不完善。具體請看這篇文章:移動端Click300ms點選延遲的來龍去脈(轉)。是以,在浏覽器開發商最終統一的解決方案出來之前,我們還有一些基于Javascript的現成的解決方案可以用。

1、指針事件的polyfill

現在除了IE,其他大部分浏覽器都還不支援指針事件。有一些JS庫,可以讓我們提前使用指針事件,比如

Google 的 Polymer

微軟的 HandJS

@Rich-Harris的 Points

然而,我們現在關心的不是指針事件,而是與300ms延遲相關的CSS屬性

touch-action

。由于除了IE之外的大部分浏覽器都不支援這個新的CSS屬性,是以這些指針事件的polyfill必須通過某種方式去模拟支援這個屬性。一種方案是JS去請求解析所有的樣式表,另一種方案是将

touch-action

作為html标簽的屬性。

2、zepto等庫的 tap事件

zepto 的touch子產品中自定義了tap事件,用于代替click事件,表示一個輕擊操作。touch子產品實作tap的原理是綁定事件touchstart,touchmove和touchend到document上,然後通過計算touch事件觸發的時間差,位置差來實作了自定義的tap,swipe等。

zepto自定義的tap操作雖然可以解決300ms點選延遲問題,但存在著名的“點透”問題。解決辦法可以參考https://segmentfault.com/a/1190000003848737

3、FastClick

FastClick 是 FT Labs 專門為解決移動端浏覽器 300 ms點選延遲問題所開發的一個輕量級的庫。FastClick的實作原理是在檢測到touchend事件的時候,會通過DOM自定義事件立即出發模拟一個click事件,并把浏覽器在300ms之後的click事件阻止掉。

其中jquery的使用方式:https://github.com/ftlabs/fastclick

$(function() {
	FastClick.attach(document.body);
});
           

總結:

禁用縮放:簡單,但同時也使的網頁無法縮放,不适用于未對移動端浏覽做适配優化的網頁。

更改預設視口寬度:簡單,但需要浏覽器支援。

指針事件和css touch-action:新屬性,可能存在浏覽器相容問題,如僅為解決點選延遲問題兒引入一整套指針事件有點過了。

tap事件:能較好解決點選延遲,并且對其他移動端觸摸事件也有較好支援,但存在點透問題。

fastclick:目前較好的專門解決點選延遲的庫,腳本尺寸相對較大。推薦使用

參考文獻:

https://segmentfault.com/a/1190000003848737

https://www.jianshu.com/p/16d3e4f9b2a9

https://www.jianshu.com/p/6e2b68a93c88