天天看點

移動端300ms相容問題(移動端經典問題)

移動端300ms延遲原因

2007 年初。蘋果公司在釋出首款 iPhone 前夕,遇到一個問題:當時的網站都是為大螢幕裝置所設計的。于是蘋果的工程師們做了一些約定,應對 iPhone 這種小螢幕浏覽桌面端站點的問題。

​輕按兩下縮放(double tap to zoom)​

​,這也是會有上述 300 毫秒延遲的主要原因。輕按兩下縮放,即用手指在螢幕上快速點選兩次,iOS 自帶的 Safari 浏覽器會将網頁縮放至原始比例。

假定這麼一個場景。使用者在 iOS Safari 裡邊點選了一個連結。由于使用者可以進行輕按兩下縮放或者單擊跳轉的操作,當使用者一次點選螢幕之後,浏覽器并不能立刻判斷使用者是确實要打開這個連結,還是想要進行輕按兩下操作。是以,iOS Safari 就等待 300 毫秒,以判斷使用者是否再次點選了螢幕。

鑒于iPhone的成功,其他移動浏覽器都複制了 iPhone Safari 浏覽器的多數約定,包括輕按兩下縮放,幾乎現在所有的移動端浏覽器都有這個功能。

解決方案

1. faskclick ​​https://github.com/ftlabs/fastclick​​

  • 原理: 在檢測到touchend事件的時候,會通過DOM自定義事件立即出發模拟一個click事件,并把浏覽器在300ms之後真正的click事件阻止掉
  • 缺點: 腳本相對較大, 不建議使用

2.禁用遊覽器縮放

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

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

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

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

一開始,因為輕按兩下縮放主要是用來改善桌面站點在移動端浏覽體驗的。 随着發展現在都是專門為移動開發專門的站點,這個時候就不需要輕按兩下縮放了,是以移動端浏覽器就可以自動禁掉預設的輕按兩下縮放行為并且去掉300ms的點選延遲。如果設定了上述meta标簽,那浏覽器就可以認為該網站已經對移動端做過了适配和優化,就無需輕按兩下縮放操作了。

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

4.通過 touchstart 和 touchend模拟實作

能不能直接用​​touchstart​​​代替click呢,

答案是不能,使用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元素是一個連結,那此時頁面就會意外地跳轉。