我們知道捲動回應速度是影響使用者與行動裝置網站的互動程度,而觸控事件監聽器通常也會造成嚴重捲動的效能問題。為解決這個問題,Chrome 允許觸控事件監聽器被動 (將 {passive: true}
選項傳遞至 addEventListener()
) 並傳送指標事件 API。這些非常實用的功能,可以將新內容引導到不會封鎖捲動的模型,但開發人員有時可能難以理解及採用。
我們認為網路應該是快速執行的關鍵,而開發人員不需要瞭解瀏覽器行為的外加細節。在 Chrome 56 版中,我們將預設輕觸被動式監聽器,在最常符合開發人員意圖的情況下使用這類模式。我們認為這麼做能大幅改善使用者體驗,並將網站受到的負面影響降到最低。
在極少數情況下,這項變更可能會導致意外捲動。通常只要套用觸控動作:無樣式至不應進行捲動的元素,即可輕鬆解決這個問題。請繼續閱讀下文,瞭解詳細資訊、如何判斷是否受到影響,以及您可以採取哪些行動。
背景:可取消事件會使網頁速度變慢
如果在 touchstart
或第一個 touchmove
事件中呼叫 preventDefault(),可防止捲動。問題在於,大多數事件監聽器不會呼叫 preventDefault()
,但瀏覽器必須等待事件完成才能確認這一點。由開發人員定義的「被動事件監聽器」可以解決這個問題。當您在事件處理常式中加入包含 {passive: true}
物件的觸控事件做為第三個參數,就表示 touchstart
事件監聽器不會呼叫 preventDefault()
,瀏覽器也可以安全地執行捲動,而不會封鎖事件監聽器。例如:
window.addEventListener("touchstart", func, {passive: true} );
幹預
我們的主要動機,是減少使用者輕觸螢幕後更新顯示畫面的時間。為瞭解觸控啟動和觸控移動的使用情形 我們新增了指標,以決定捲動封鎖行為發生的頻率
我們查看了傳送至根目標 (視窗、文件或主體) 的可取消觸控事件百分比,並確定約有 80% 的事件監聽器在概念上被動地被動,但並未登錄。鑑於這個問題的規模如此,我們發現只要將這些事件自動「被動」改為自動「被動」,就能改善捲動畫面效果,不需要任何開發人員操作。
因此,我們可以將幹預定義為:如果觸控啟動或觸控移動事件監聽器的目標為 window
、document
或 body
,則建議將 passive
預設為 true
。這表示程式碼包括:
window.addEventListener("touchstart", func);
相當於:
window.addEventListener("touchstart", func, {passive: true} );
現在,系統會忽略事件監聽器中對 preventDefault()
的呼叫。
下圖顯示從使用者輕觸螢幕並捲動至顯示更新時間的前 1% 捲動所花費的時間。這項資料適用於 Android 版 Chrome 中的所有網站。在進入介入措施啟用前
1% 的捲動只花了 400 毫秒以上該版本現已在 Chrome 56 Beta 版中縮減為 250 毫秒以上,縮減約 38%。我們期望未來能將所有 touchstart
和 touchmove
事件監聽器設為被動 true 的預設值,減少到 50 毫秒以下。
破壞和指引
在大多數情況下,系統不會察覺到任何中斷情形。不過,如果發生中斷情形,最常見的原因就是捲動操作,異常終止的情形發生。在極少數情況下,開發人員可能會發現非預期的點擊事件 (當 touchend
事件監聽器缺少 preventDefault()
)。
在 Chrome 56 以上版本中,如果在啟用介入措施的情況下呼叫 preventDefault()
,開發人員工具會記錄警告。
touch-passive.html:19 Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
應用程式可檢查透過 defaultPrevented
屬性呼叫 preventDefault
是否產生任何效果,以判斷可能在野外進行這項設定。
我們發現,多數受影響的網頁只要盡可能套用 touch-action CSS 屬性,就能以相對輕鬆的方式修正。如果想避免所有瀏覽器捲動及縮放元素元素,請對該元素套用 touch-action: none
。如果您有水平輪轉介面,請考慮對其套用 touch-action: pan-y pinch-zoom
,讓使用者仍可垂直捲動及縮放,一切都如常。對於支援指標事件和觸控事件的瀏覽器 (例如電腦版 Edge) 的瀏覽器,您仍須正確套用觸控動作。如果是行動版 Safari 和舊版行動瀏覽器不支援觸控動作,則觸控事件監聽器必須繼續呼叫 preventDefault
,即使 Chrome 會忽略這個類別也一樣。
若是較複雜的情況,可能還需要仰賴下列其中一個選項:
- 如果
touchstart
事件監聽器呼叫preventDefault()
,請確保系統會從相關聯的觸控端事件監聽器呼叫 preventDefault(),以便繼續抑制點擊事件產生和其他預設輕觸行為。 - 最後 (不建議) 傳遞
{passive: false}
至 addEventListener(),藉此覆寫預設行為。請注意,您必須偵測使用者代理程式是否支援 EventListenerOptions。
結語
Chrome 56 的捲動速度在許多網站上已大幅加快。這是多數開發人員因這項異動而注意到的影響。在某些情況下,開發人員可能會發現非預期的捲動功能。
雖然行動裝置 Safari 仍須這麼做,但網站不應仰賴 touchstart
和 touchmove
事件監聽器中的 preventDefault()
,因為 Chrome 已無法保證這項服務。開發人員應將 touch-action
CSS 屬性套用至應該停用捲動和縮放功能的元素,以便在發生任何觸控事件前通知瀏覽器。如要隱藏輕觸的預設行為 (例如產生點擊事件),請在 touchend
事件監聽器中呼叫 preventDefault()
。