1. 程式人生 > >移動端300ms的點擊延遲以及解決方案

移動端300ms的點擊延遲以及解決方案

string 明顯 而是 一段 通過 然而 監聽 屬性 sca

【今天做在移動端的一些效果時,我選擇使用動畫而不是用過渡,這個300ms的點擊延遲是我為什麽使用動畫而不使用過渡最主要的一個原因】

動畫和過渡

共同點:都是css控制DOM運動,

不同點:

1、過渡:只有兩個關鍵幀,開始和結束;

2、動畫可以設置多個關鍵幀

3、過渡必須通過事件去觸發

4、動畫不需要打開即可運動

【CSS執行速度更快,js事件觸發執行,手機端點擊類事件則會遇上300ms點擊延遲,用戶體驗更差】

一、移動端300ms點擊延遲

一般情況下,如果沒有經過特殊處理,移動端瀏覽器在派發點擊事件的時候,通常會出現300ms左右的延遲。也就是說,當我們點擊頁面的時候移動端瀏覽器並不是立即作出反應,而是會等上一小會兒才會出現點擊的效果。在移動WEB興起的初期,用戶對300ms的延遲感覺不明顯。但是,隨著用戶對交互體驗的要求越來越高,現今,移動端300ms的點擊延遲逐漸變得明顯而無法忍受。

那麽,移動端300ms的點擊延遲是怎麽來的呢?

問題由來
這要追溯至 2007 年初。蘋果公司在發布首款 iPhone 前夕,遇到一個問題:當時的網站都是為大屏幕設備所設計的。於是蘋果的工程師們做了一些約定,應對 iPhone 這種小屏幕瀏覽桌面端站點的問題。

這當中最出名的,當屬雙擊縮放(double tap to zoom),這也是會有上述 300 毫秒延遲的主要原因。

雙擊縮放,顧名思義,即用手指在屏幕上快速點擊兩次,iOS 自帶的 Safari 瀏覽器會將網頁縮放至原始比例。 那麽這和 300 毫秒延遲有什麽聯系呢? 假定這麽一個場景。用戶在 ios Safari 裏邊點擊了一個鏈接。由於用戶可以進行雙擊縮放或者雙擊滾動的操作,當用戶一次點擊屏幕之後,瀏覽器並不能立刻判斷用戶是確實要打開這個鏈接,還是想要進行雙擊操作。因此,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點擊了屏幕。 鑒於iPhone的成功,其他移動瀏覽器都復制了 iPhone Safari 瀏覽器的多數約定,包括雙擊縮放,幾乎現在所有的移動端瀏覽器都有這個功能。

之前人們剛剛接觸移動端的頁面,在欣喜的時候往往不會care這個300ms的延時問題,可是如今touch端界面如雨後春筍,用戶對體驗的要求也更高,這300ms帶來的卡頓慢慢變得讓人難以接受。

也就是說,移動端瀏覽器會有一些默認的行為,比如雙擊縮放、雙擊滾動。這些行為,尤其是雙擊縮放,主要是為桌面網站在移動端的瀏覽體驗設計的。而在用戶對頁面進行操作的時候,移動端瀏覽器會優先判斷用戶是否要觸發默認的行為。

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

瀏覽器開發商的解決方案

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

目前,瀏覽器開發商的解決方案主要有一下三種方案:
方案一:禁用縮放
當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庫,可以讓我們提前使用指針事件,比如

  • Google 的 Polymer
  • 微軟的 HandJS
  • @Rich-Harris 的 Points

  然而,我們現在關心的不是指針事件,而是與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元素是一個鏈接,那此時頁面就會意外地跳轉。

移動端300ms的點擊延遲以及解決方案