Update 2020/05/05 12:00 Chrome 瀏覽器在當前版本(v81)已經沒有這個問題,本文就留做記念吧!(我想應該更早就已經修正了,但我遲遲沒有重新檢查)
前端也是做了很久,直到最近才發現這個事實,感覺有點羞愧 ww 為了讓同樣的事情不要再重演,決定專文說明之!
以下文章的內容基本以 Chrome 瀏覽器作為展示用的平台,所以一些 render performance 的問題不見得會出你家的瀏覽器上,畢竟各家瀏覽器為了讓使用者能夠順暢瀏覽網頁,可能還是有做一些各自的調整。
現在已知的是 Opera 在本文主題的範圍內所受的影響與 Chrome 是一樣的(同為 Blink引擎)。
scrollable <div>
其實直接看一下 CSS 就明白我的意思啦
.scrollable {
height: 100%;
overflow: auto;
}
其實就是帶有捲軸的 <div>
而已,它的特性是在內容超出設定的 寬度/高度 之後會出現捲軸(用 overflow: scroll
的話,會一直有捲軸)
捲動重繪問題,初次見面!
其實就是在新版的 手打 首頁。
其實一開始還感覺不大出來,但多捲幾下之後發現這個捲動的吃力程度連我的(三年前的)超級遊戲桌機都有點受不了,馬上來用 Chrome DevTools 看兩把!
從圖中可以清楚的看到每個 frame 中有很長的時間用在 painting,並且很多 frame 的運作時間超過 16~17ms,造成整體的 fps 沒辦法達到 60。
簡單的重現
Preview 的時候先按「Launch the preview in a separate window」在新視窗開啟,再來打開 DevTools 觀察比較準(原本擺在 iframe 裡可能會影響結果)
確認的方法就是開啟 DevTools 裡的「Enable paint flashing」,就可以在捲動的時候看到重繪的區域。
捲動時不重繪
https://plnkr.co/edit/Xg80bahiQcGZyVWqnp6W?p=preview
捲動時重繪
https://plnkr.co/edit/UGDn3QOeET57SGuCPByk?p=preview
簡單的 workaround
其實以往會用到這樣的 <div>
的部分在網頁上並不多見,可能相對在 web app 裡面比較多見;然而現在隨著網頁設計/網頁技術的演進,出現各種嶄新的 layout 方法,於是 scrollable <div>
也變得不是這麼少見,而區塊也不見得是小小一塊(像 手打 就是整個內容全包在裡面)。
換句話說,要是你頭已經洗下去了,怎麼快速的挽救。
其實做法非常簡單,只要用 webkit/blink 引擎的神秘萬靈丹 -> 推到 composite layer 就好了
推到 composite layer 的方法也要與時俱進,從 Chrome 36 以後就可以用 will-change: transform
來建立新 layer。
(更多關於 will-change
的資訊可以看: https://dev.opera.com/articles/css-will-change-property/)
把 will-change: transform
加在 捲動的那個 <div>
上,即完成修正!
.scrollable {
height: 100%;
overflow: auto;
will-change: transform; /* yeah ! */
}
捲動時重繪 -> 修正成果
https://plnkr.co/edit/ZrFj9Gh9JrafHx6q1pPf?p=preview
Material Design Lite
其實上面有說到 各種嶄新的 layout 方法 說的就是 Material Design Lite。
稍微看一下就會發現它的 layout 完全是基於層層的 flexbox,然後最外層會用一個 position: absolute
的滿版 <div>
全部包起來。
換句話說只要是使用 Material Design Lite,你的整個網頁內容都會是包在 scrollable <div>
裡…
對,新版的 手打 就是套用了使用 Materia Design Lite 所以才會有捲動重會比較嚴重的現象。
所以同樣的到 MDL 官網捲看看會發現他們也是一直重繪。
TL;DR
內部可捲動的 <div>
- 不做任何處理的話,會在捲動的時候重繪內容
- 如果版面很大、內容複雜,重繪很吃捲動效能
- 例: Material Design Lite
解決方法
- 將關鍵的
<div>
推到 composite layer - 使用新的
will-change: transform
後記
新版 手打 網站其實在撰文的時候已經透過上面的 workaround 修正了 XD
主要還是想說 MDL 超先進 layout 方法真是表翻了 Blink引擎 的瀏覽器(感覺受 scrollable <div>
影響效能較別的瀏覽器嚴重)… 明明算是 Google 自家出品的啊 www
其實這個問題有人在 MDL 那邊開了 issue,不過目前看似被放置了。