通常狀況下,若是沒有通過特殊處理,移動端瀏覽器在派發點擊事件的時候,一般會出現300ms左右的延遲。也就是說,當咱們點擊頁面的時候移動端瀏覽器並非當即做出反應,而是會等上一小會兒纔會出現點擊的效果。在移動WEB興起的初期,用戶對300ms的延遲感受不明顯。可是,隨着用戶對交互體驗的要求愈來愈高,現今,移動端300ms的點擊延遲逐漸變得明顯而沒法忍受。html
那麼,移動端300ms的點擊延遲是怎麼來的呢?git
問題由來
這要追溯至 2007 年初。蘋果公司在發佈首款 iPhone 前夕,遇到一個問題:當時的網站都是爲大屏幕設備所設計的。因而蘋果的工程師們作了一些約定,應對 iPhone 這種小屏幕瀏覽桌面端站點的問題。github
這當中最出名的,當屬雙擊縮放(double tap to zoom),這也是會有上述 300 毫秒延遲的主要緣由。web
雙擊縮放,顧名思義,即用手指在屏幕上快速點擊兩次,iOS 自帶的 Safari 瀏覽器會將網頁縮放至原始比例。 那麼這和 300 毫秒延遲有什麼聯繫呢? 假定這麼一個場景。用戶在 iOS Safari 裏邊點擊了一個連接。因爲用戶能夠進行雙擊縮放或者雙擊滾動的操做,當用戶一次點擊屏幕以後,瀏覽器並不能馬上判斷用戶是確實要打開這個連接,仍是想要進行雙擊操做。所以,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點擊了屏幕。 鑑於iPhone的成功,其餘移動瀏覽器都複製了 iPhone Safari 瀏覽器的多數約定,包括雙擊縮放,幾乎如今全部的移動端瀏覽器都有這個功能。以前人們剛剛接觸移動端的頁面,在欣喜的時候每每不會care這個300ms的延時問題,但是現在touch端界面如雨後春筍,用戶對體驗的要求也更高,這300ms帶來的卡頓慢慢變得讓人難以接受。瀏覽器
也就是說,移動端瀏覽器會有一些默認的行爲,好比雙擊縮放、雙擊滾動。這些行爲,尤爲是雙擊縮放,主要是爲桌面網站在移動端的瀏覽體驗設計的。而在用戶對頁面進行操做的時候,移動端瀏覽器會優先判斷用戶是否要觸發默認的行爲。app
那有什麼辦法能夠解決這個問題呢?webapp
瀏覽器開發商要對移動端瀏覽器自己的設計進行改善,以提供長遠的解決方案。函數
目前,瀏覽器開發商的解決方案主要有一下三種方案:
方案一:禁用縮放
當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庫,可讓咱們提早使用指針事件,好比
然而,咱們如今關心的不是指針事件,而是與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元素是一個連接,那此時頁面就會意外地跳轉。
移動端Click300毫秒點擊延遲的前因後果(轉)
移動端click事件延遲300ms究竟是怎麼回事,該如何解決?
詳細解析-移動H5點擊穿透現象