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

戴夫塔普斯卡
Dave Tapuska

我們知道捲動回應速度是影響使用者與行動裝置網站的互動程度,而觸控事件監聽器通常也會造成嚴重捲動的效能問題。為解決這個問題,Chrome 允許觸控事件監聽器被動 (將 {passive: true} 選項傳遞至 addEventListener()) 並傳送指標事件 API。這些非常實用的功能,可以將新內容引導到不會封鎖捲動的模型,但開發人員有時可能難以理解及採用。

我們認為網路應該是快速執行的關鍵,而開發人員不需要瞭解瀏覽器行為的外加細節。在 Chrome 56 版中,我們將預設輕觸被動式監聽器,在最常符合開發人員意圖的情況下使用這類模式。我們認為這麼做能大幅改善使用者體驗,並將網站受到的負面影響降到最低。

在極少數情況下,這項變更可能會導致意外捲動。通常只要套用觸控動作樣式至不應進行捲動的元素,即可輕鬆解決這個問題。請繼續閱讀下文,瞭解詳細資訊、如何判斷是否受到影響,以及您可以採取哪些行動。

背景:可取消事件會使網頁速度變慢

如果在 touchstart 或第一個 touchmove 事件中呼叫 preventDefault(),可防止捲動。問題在於,大多數事件監聽器不會呼叫 preventDefault(),但瀏覽器必須等待事件完成才能確認這一點。由開發人員定義的「被動事件監聽器」可以解決這個問題。當您在事件處理常式中加入包含 {passive: true} 物件的觸控事件做為第三個參數,就表示 touchstart 事件監聽器不會呼叫 preventDefault(),瀏覽器也可以安全地執行捲動,而不會封鎖事件監聽器。例如:

window.addEventListener("touchstart", func, {passive: true} );

幹預

我們的主要動機,是減少使用者輕觸螢幕後更新顯示畫面的時間。為瞭解觸控啟動和觸控移動的使用情形 我們新增了指標,以決定捲動封鎖行為發生的頻率

我們查看了傳送至根目標 (視窗、文件或主體) 的可取消觸控事件百分比,並確定約有 80% 的事件監聽器在概念上被動地被動,但並未登錄。鑑於這個問題的規模如此,我們發現只要將這些事件自動「被動」改為自動「被動」,就能改善捲動畫面效果,不需要任何開發人員操作。

因此,我們可以將幹預定義為:如果觸控啟動或觸控移動事件監聽器的目標為 windowdocumentbody,則建議將 passive 預設為 true。這表示程式碼包括:

window.addEventListener("touchstart", func);

相當於:

window.addEventListener("touchstart", func, {passive: true} );

現在,系統會忽略事件監聽器中對 preventDefault() 的呼叫。

下圖顯示從使用者輕觸螢幕並捲動至顯示更新時間的前 1% 捲動所花費的時間。這項資料適用於 Android 版 Chrome 中的所有網站。在進入介入措施啟用前 1% 的捲動只花了 400 毫秒以上該版本現已在 Chrome 56 Beta 版中縮減為 250 毫秒以上,縮減約 38%。我們期望未來能將所有 touchstarttouchmove 事件監聽器設為被動 true 的預設值,減少到 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) 的瀏覽器,您仍須正確套用觸控動作。如果是行動版 Safari 和舊版行動瀏覽器不支援觸控動作,則觸控事件監聽器必須繼續呼叫 preventDefault,即使 Chrome 會忽略這個類別也一樣。

若是較複雜的情況,可能還需要仰賴下列其中一個選項:

  • 如果 touchstart 事件監聽器呼叫 preventDefault(),請確保系統會從相關聯的觸控端事件監聽器呼叫 preventDefault(),以便繼續抑制點擊事件產生和其他預設輕觸行為。
  • 最後 (不建議) 傳遞 {passive: false} 至 addEventListener(),藉此覆寫預設行為。請注意,您必須偵測使用者代理程式是否支援 EventListenerOptions

結語

Chrome 56 的捲動速度在許多網站上已大幅加快。這是多數開發人員因這項異動而注意到的影響。在某些情況下,開發人員可能會發現非預期的捲動功能。

雖然行動裝置 Safari 仍須這麼做,但網站不應仰賴 touchstarttouchmove 事件監聽器中的 preventDefault(),因為 Chrome 已無法保證這項服務。開發人員應將 touch-action CSS 屬性套用至應該停用捲動和縮放功能的元素,以便在發生任何觸控事件前通知瀏覽器。如要隱藏輕觸的預設行為 (例如產生點擊事件),請在 touchend 事件監聽器中呼叫 preventDefault()