我們知道滾動響應(yīng)是至關(guān)重要的在用戶移動端網(wǎng)站上觸摸的時候,然而觸摸事件監(jiān)聽器經(jīng)常會導(dǎo)致嚴重的滾動性能問題明未。Chrome已經(jīng)通過允許觸摸事件監(jiān)聽器被動地解決了這個問題(將{passive:true}
選項傳遞給addEventListener()
)并傳遞指針事件API痘绎。這些特性可以驅(qū)動新內(nèi)容引入到不阻止?jié)L動的模型中兔毒,但開發(fā)人員有時會發(fā)現(xiàn)它們很難理解和采用。
我們認為,如果開發(fā)人員不需要了解瀏覽器行為的晦澀細節(jié)黄娘,web應(yīng)該在默認情況下是快速的。在Chrome 56中克滴,默認情況下逼争,我們將默認的觸摸監(jiān)聽器設(shè)置為被動的,而這通常與開發(fā)人員的意圖相匹配劝赔。我們相信這樣做誓焦,我們可以大大提高用戶的體驗,同時減少對站點的負面影響着帽。
在極少數(shù)情況下杂伟,這種變化會導(dǎo)致非預(yù)期的滾動。這通常是通過添加一個 touch-action: none
樣式使得元素滾動不再出現(xiàn)仍翰。閱讀有關(guān)細節(jié)赫粥,如何知道你是否受到影響,以及你能做些什么予借。
背景: Cancelable 事件降低你的頁面速度
如果在touchstart
或第一個touchmove
事件中調(diào)用preventDefault()
越平,那么您將阻止?jié)L動频蛔。問題是,大多數(shù)情況下秦叛,監(jiān)聽器不會調(diào)用preventDefault()
晦溪,但是瀏覽器需要等待事件完成才能確定它。開發(fā)人員定義的“被動事件監(jiān)聽器”解決了這個問題挣跋。當您在事件處理程序中添加一個帶有{passive:true}
對象作為第三個參數(shù)的觸摸事件時三圆,您將告訴瀏覽器touchstart
監(jiān)聽器不會調(diào)用preventDefault()
,而瀏覽器可以安全地執(zhí)行滾動浆劲,而不會阻塞監(jiān)聽器嫌术。例如:
window.addEventListener("touchstart", func, {passive: true} );
干預(yù) The Intervention
我們的主要目的是減少在用戶觸摸屏幕后更新顯示所需的時間。為了理解touchstart
和touchmove
的使用牌借,我們添加了一些指標來確定滾動阻塞行為發(fā)生的頻率度气。
我們看了可取消觸摸事件,被發(fā)送到根目標(窗口膨报、文檔或主體)的的百分比磷籍,并確定大約80%的監(jiān)聽器在概念上是被動的,但未被注冊為此類现柠≡毫欤考慮到這個問題的規(guī)模,我們注意到一個很大的機會够吩,可以在沒有任何開發(fā)人員操作的情況下比然,自動地passive
改進滾動。
這促使我們將我們的干預(yù)定義為:如果觸點或觸控式監(jiān)聽器的目標是窗口周循、文檔或主體强法,我們默認passive
為true
。代碼示例:
window.addEventListener("touchstart", func);
相當于
window.addEventListener("touchstart", func, {passive: true} );
現(xiàn)在湾笛,在監(jiān)聽器內(nèi)部調(diào)用preventDefault()
將被忽略饮怯。
下面的圖顯示用戶觸摸屏幕時,從用戶觸摸屏幕到顯示更新時所花費的時間嚎研。這一數(shù)據(jù)適用于所有的安卓網(wǎng)站蓖墅。在干預(yù)之前,1%的卷軸使用了400多毫秒×侔纾現(xiàn)在已經(jīng)減少到超過250ms的Chrome 56 Beta;大約減少了38%论矾。在未來,我們希望使所有touchstart
和touchmove
偵聽器的默認值都是被動的杆勇,將其降低到50毫秒以下贪壳。
問題和指導(dǎo) Breakage and Guidance
在絕大多數(shù)情況下,沒有問題靶橱。但當問題發(fā)生時寥袭,最常見的癥狀是當你不想要的時候滾動路捧。在極少數(shù)情況下,開發(fā)人員還可能注意到意外的單擊事件(在touchend
偵聽器中丟失了preventDefault()
)传黄。
在Chrome 56和稍后的版本中杰扫,當您調(diào)用preventDefault()
時,DevTools
將記錄一個警告膘掰,在這個事件中章姓,干預(yù)是激活的。
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
您的應(yīng)用程序可以通過檢查調(diào)用preventDefault
是否通過defaultPrevented
屬性來確定它是否出現(xiàn)問題识埋。
我們發(fā)現(xiàn)凡伊,只要有可能,應(yīng)用touch-action
CSS屬性就可以相對容易地修復(fù)大部分受影響頁面窒舟。 如果你希望阻止瀏覽器的滾動和縮放系忙,可以再元素中應(yīng)用touch-action: none
來實現(xiàn)。你過你需要水平的滾動惠豺,可以應(yīng)用touch-action: pan-y pinch-zoom
,這樣用戶仍然可以正常使用垂直滾動和縮放银还。在桌面邊緣等瀏覽器上,正確地應(yīng)用touch-action
已經(jīng)是必要的了洁墙,它支持指針事件蛹疯,而不是觸摸事件。對于不支持touch-action
的移動Safari和老式移動瀏覽器热监,您的觸摸監(jiān)聽器必須繼續(xù)調(diào)用preventDefault
捺弦,即使它將被Chrome忽略。
在更復(fù)雜的情況下孝扛,可能還需要依賴以下的一個:
- 如果您的
touchstart
監(jiān)聽器調(diào)用preventDefault()
列吼,確保preventDefault()
也從相關(guān)的touchend
監(jiān)聽器被調(diào)用,以繼續(xù)禁止單擊事件的生成和其他默認的點擊行為疗琉。 - 最后(不推薦)通過
{passive:false}
到addEventListener()
來覆蓋默認行為冈欢。請注意歉铝,如果用戶代理支持EventListenerOptions
盈简,則必須進行功能檢測。
總結(jié) Conclusion
在Chrome 56中太示,在許多網(wǎng)站上滾動的速度要快得多柠贤。這是大多數(shù)開發(fā)人員由于這種變化而引起的惟一影響。在某些情況下类缤,開發(fā)人員可能會注意到無意識的滾動臼勉。
盡管對于移動Safari來說仍然需要這樣做,但網(wǎng)站不應(yīng)該依賴于在touchstart
和touchmove
監(jiān)聽器內(nèi)部調(diào)用preventDefault()
餐弱,因為這不再保證在Chrome中能夠支持宴霸。開發(fā)人員應(yīng)該在滾動和縮放的元素上應(yīng)用touch-action
CSS屬性囱晴,在發(fā)生任何觸摸事件之前通知瀏覽器。要禁止點擊的默認行為(例如單擊事件生成)瓢谢,請在touchend
監(jiān)聽器內(nèi)部調(diào)用preventDefault()
畸写。