預設將觸控捲動功能設為快速

Dave Tapuska
Dave Tapuska

我們知道,捲動回應速度對使用者與行動版網站的互動至關重要,但觸控事件事件監聽器經常會導致嚴重的捲動效能問題。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 事件監聽器的目標是 windowdocumentbody,我們會將 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」設為 所有 touchstarttouchmove 事件監聽器的預設值,將這項作業時間縮短至 50 毫秒以下。

前 1% 捲動次數圖表

服務中斷和指南

在絕大多數情況下,不會發生破損情形。但當中斷確實發生時,最常見的症狀是在您不想捲動時,系統仍會捲動。在極少數情況下,開發人員也可能會發現意外的點擊事件 (當 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 執行這項操作,但網站不應依賴在 touchstarttouchmove 事件監聽器內呼叫 preventDefault(),因為 Chrome 不再保證會執行這項操作。開發人員應在應停用捲動和縮放功能的元素上套用 touch-action CSS 屬性,以便在任何觸控事件發生前通知瀏覽器。如要抑制輕觸的預設行為 (例如產生點擊事件),請在 touchend 事件監聽器中呼叫 preventDefault()