文章目錄
一、移動端點擊產生300 ms的延遲
300ms延遲是指當我們點擊頁面的時候移動端瀏覽器並不是立即作出反應,而是會等上300ms纔會出現點擊的效果。
而設置這300ms的意義在於判斷用戶的雙擊行爲。移動端瀏覽器會有一些默認的行爲,比如雙擊縮放、雙擊滾動。這些行爲,尤其是雙擊縮放,主要是爲桌面網站在移動端的瀏覽體驗設計的。
在移動web的興起初期,人們對這個問題的感知並不明顯,但隨着用戶對交互體驗的要求越來越高,現今,移動端300ms的點擊延遲逐漸變得明顯而無法忍受。
解決方案
目前,瀏覽器開發商的解決方案主要有一下三種方案:
方案一:禁用縮放(HTML文檔頭部設置meta標籤)
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">
這種方法的缺點顯而易見,我們犧牲了縮放的功能。但實際需求中,我們還是希望能通過雙指還實現縮放的。我們不想要的只是雙擊縮放行爲。
方案二:更改默認的視口寬度
設置視口寬度爲設備寬度:
<meta name="viewport" content="width=device-width">
如果設置了上述meta標籤,那瀏覽器就可以認爲該網站已經對移動端做過了適配和優化,就無需雙擊縮放操作了。
這個方案相比方案一的好處在於,它沒有完全禁用縮放,而只是禁用了瀏覽器默認的雙擊縮放行爲,但用戶仍然可以通過雙指縮放操作來縮放頁面。
方案三:CSS touch-action
CSS屬性touch-action
用於設置觸摸屏用戶如何操縱元素的區域(例如,瀏覽器內置的縮放功能)。
如果將該屬性值設置爲touch-action: none
,那麼表示在該元素上的操作不會觸發用戶代理的任何默認行爲,就無需進行300ms的延遲判斷。
由於除了IE之外的大部分瀏覽器都不支持這個新的CSS屬性,所以指針事件的polyfill必須通過某種方式去模擬支持這個屬性。一種方案是JS去請求解析所有的樣式表,另一種方案是將touch-action
作爲html標籤的屬性。
Polyfill 是一塊代碼(通常是 Web 上的 JavaScript),用來爲舊瀏覽器提供它沒有原生支持的較新的功能。
方案四:FastClick
FastClick 是 FT Labs 專門爲解決移動端瀏覽器 300 毫秒點擊延遲問題所開發的一個輕量級的庫。
FastClick的實現原理是在檢測到touchend事件的時候,會通過DOM自定義事件立即出發模擬一個click事件,並把瀏覽器在300ms之後的click事件阻止掉。
//引入fastclick
<script src="js/fastclick.min.js"></script>
// 原生js初始化
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
方案五:使用touchstart替代click
可能有人會想,既然click點擊有300ms的延遲,那對於觸摸屏,我們直接監聽touchstart事件不就好了嗎?
事實上,使用touchstart去代替click事件有兩個不好的地方。
第一:touchstart是手指觸摸屏幕就觸發,有時候用戶只是想滑動屏幕,卻觸發了touchstart事件,這不是我們想要的結果;
第二:使用touchstart事件在某些場景下可能會出現點擊穿透的現象。下面講一講點擊穿透。
二、點擊穿透
什麼是點擊穿透,點擊穿透爲什麼會發生
假如頁面上有兩個元素A和B。B元素在A元素之上。我們在B元素的touchstart
事件上註冊了一個回調函數,該回調函數的作用是隱藏B元素。我們發現,當我們點擊B元素,B元素被隱藏了,隨後,A元素觸發了click
事件。當然前提是A元素上綁定了click
事件,或者說,A元素是個鏈接<a>
、輸入框<input>
等。
這是因爲在移動端瀏覽器,事件執行的順序是touchstart > touchend > click
。而click事件有300ms的延遲,當touchstart
事件把B元素隱藏之後,隔了300ms,瀏覽器觸發了click
事件,但是此時B元素不見了,所以該事件被派發到了A元素身上。如果A元素是一個鏈接,那此時頁面就會意外地跳轉。
什麼時候會觸發點擊穿透
click只是在移動端有300ms的延遲,因此,在移動端開發時,混用click和touch會導致穿透事件。
解決方案
延遲蒙層的消失時間
對於設置蒙層的穿透,可以將這個蒙層消失的時間後移350ms,當然爲了不讓用戶感覺到卡頓,可以先設置這個蒙層的opacity
透明度爲0,然後等350ms後,再設置display:none
。
CSS touch-action
和之前說到的一樣,將touch-action
設置爲none
,使被覆蓋元素的click事件無法發生。當然我們需要在350ms之後解除這個鎖定,將touch-action
恢復爲auto
。
這種方法的缺點就在於兼容性問題。
使用FastClick
使用fastclick庫,從此所有的點擊事件都使用click,而且不存在300ms延遲。當然也就沒有了點擊穿透問題。
fastclick的用法上面也有談到。