我們知道,捲動回應速度對使用者與行動版網站的互動至關重要,但觸控事件事件監聽器經常會導致嚴重的捲動效能問題。Chrome 已解決這個問題,方法是允許觸控事件事件監聽器為被動 (將 {passive: true}
選項傳遞至 addEventListener()
),並提供 指標事件 API。這些功能非常適合將新內容導入不阻擋捲動的模型,但開發人員有時會發現這些功能難以理解及採用。
我們認為,網頁應預設為快速,開發人員不必瞭解瀏覽器行為的神秘細節。在 Chrome 56 中,如果開發人員的用心與預設值相符,我們會將觸控事件監聽器預設為被動。我們相信,這樣做可大幅改善使用者體驗,同時對網站造成的負面影響降到最低。
在少數情況下,這項變更可能會導致無意義的捲動。只要將 touch-action: none 樣式套用至不應捲動的元素,通常就能輕鬆解決這個問題。請繼續閱讀,瞭解相關詳細資訊、如何判斷是否受到影響,以及可採取的行動。
背景資訊:可取消的事件會使網頁載入速度變慢
如果您在 touchstart
或第一個 touchmove
事件中呼叫 preventDefault(),就會防止捲動。問題是,大多數情況下,事件監聽器不會呼叫 preventDefault()
,但瀏覽器需要等待事件完成,才能確定這點。開發人員定義的「被動事件監聽器」可解決這個問題。當您在事件處理常式中新增觸控事件,並將 {passive: true}
物件做為第三個參數,則表示您告訴瀏覽器 touchstart
事件監聽器不會呼叫 preventDefault()
,且瀏覽器可安全執行捲動動作,而不會阻斷事件監聽器。例如:
window.addEventListener("touchstart", func, {passive: true} );
介入
我們的主要動機是減少使用者觸碰螢幕後,更新螢幕畫面所需的時間。為了瞭解 touchstart 和 touchmove 的使用情形,我們新增了指標,用來判斷捲動阻擋行為發生的頻率。
我們查看了傳送至根目錄目標 (視窗、文件或主體) 的取消鍵觸控事件百分比,並判斷其中約 80% 的事件監聽器在概念上為被動,但並未註冊為此類事件。考量到這個問題的規模,我們發現有絕佳機會可讓這些事件自動設為「被動」,無須任何開發人員動作就能改善捲動功能。
因此,我們將介入方式定義為:如果 touchstart 或 touchmove 事件監聽器的目標是 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%。我們希望日後將「passive true」設為 所有 touchstart
和 touchmove
事件監聽器的預設值,將這項作業時間縮短至 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) 上,正確套用 touch-action 已是必要條件。針對行動版 Safari 和不支援 touch-action 的舊版行動瀏覽器,觸控事件監聽器必須繼續呼叫 preventDefault
,即使 Chrome 會忽略該事件也一樣。
在較複雜的情況下,您可能還需要依賴下列其中一種做法:
- 如果
touchstart
事件監聽器呼叫preventDefault()
,請確認從相關的 touchend 事件監聽器也呼叫 preventDefault(),以便繼續抑制產生點擊事件和其他預設輕觸行為。 - 最後 (且不建議) 將
{passive: false}
傳遞至 addEventListener(),以覆寫預設行為。請注意,您必須使用功能偵測 User Agent 是否支援 EventListenerOptions。
結論
在 Chrome 56 中,許多網站的捲動速度明顯提升。這是大多數開發人員會注意到的唯一影響。在某些情況下,開發人員可能會發現無意義的捲動。
雖然仍須為行動版 Safari 執行這項操作,但網站不應依賴在 touchstart
和 touchmove
事件監聽器內呼叫 preventDefault()
,因為 Chrome 不再保證會執行這項操作。開發人員應在應停用捲動和縮放功能的元素上套用 touch-action
CSS 屬性,以便在任何觸控事件發生前通知瀏覽器。如要抑制輕觸的預設行為 (例如產生點擊事件),請在 touchend
事件監聽器中呼叫 preventDefault()
。