原文地址:What Exactly Is..... The 300ms Click Delayjavascript
快速響應是全部 UI 實現的重中之重。研究代表,當延遲超過 100 毫秒,用戶就能感覺到界面的卡頓。 然而,出於對手指觸摸滑動的區分,移動端頁面對於觸摸事件會有 300 毫秒的延遲,致使多數用戶感受移動設備上基於 HTML 的 web 應用界面響應速度慢。 本文主要討論上述延時的來歷,瀏覽器生產商的考慮,以及咱們做爲開發者,當前應該如何處理這個問題。css
這要追溯至 2007 年初。蘋果公司在發佈首款 iPhone 前夕,遇到一個問題 —— 當時的網站都是爲大屏幕設備所設計的。因而蘋果的工程師們作了一些約定,應對 iPhone 這種小屏幕瀏覽桌面端站點的問題。html
這當中最出名的,當屬雙擊縮放(double tap to zoom)。這也是會有上述 300 毫秒延遲的主要緣由。java
雙擊縮放,顧名思義,即用手指在屏幕上快速點擊兩次,iOS 自帶的 Safari 瀏覽器會將網頁縮放至原始比例。ios
下面以這篇網站響應時間的文章頁面爲例,剛一打開頁面,除了文章自己,咱們還看到頂部通欄、菜單等非關鍵性要素。git
咱們進入這個頁面的目的顯然是爲了閱讀這篇文章。因此當咱們雙擊屏幕時,Safari 會至關智能地縮放至主體文章。github
上述例子代表,iOS Safari 在雙擊後準確地定位到頁面主體文章,並將其縮放至適合比例展示。這也至關符合我的使用習慣。web
那麼這和 300 毫秒延遲有什麼聯繫呢?瀏覽器
假定這麼一個場景。用戶在 iOS Safari 裏邊點擊了一個連接。因爲用戶能夠進行雙擊縮放或者雙擊滾動的操做,當用戶一次點擊屏幕以後,瀏覽器並不能馬上判斷用戶是確實要打開這個連接,仍是想要進行雙擊操做。所以,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點擊了屏幕。app
因而,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 開發團隊最近提出了更好的方式。
除了雙擊縮放的約定外,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 毫秒點擊延遲的所有內容了,但別急,還有一個值得討論的方案 —— 指針事件。
指針事件最初由微軟提出,現已進入 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 比較多,如下列出比較流行的幾個。
爲避免 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 是 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 的用戶,那你徹底沒必要擔憂上述問題。一個自定義的點擊延遲解決方案已經做爲 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 的指針事件等,更屬長久之計。
將來發展如何,讓咱們拭目以待。