- 其實瀏覽器解析 CSS 的速度非常快
- 不能因為 CSS不會對性能產生「巨大」的影響,就自顧自的亂寫一通
效能優化是一段追求好還要更好的過程。
CSS Selector
- CSS Selector 的匹配原則是「從右向左進行的」
- 這個最右側的選擇器又被稱作「關鍵選擇器」。
不同 CSS Selector 的性能
- 效能排列從上到下效能由高到低 (ID Selector 與 Class Selector 效能其實差異不大)
CSS Selector 最佳化的 Tips
- 千萬不要亂用萬用字元 * (想像成SQL的SELECT * FROM)
- 避免在 ID 或是 Class Selector 前面限定元素類型
- Child Combinator 子選擇器 優先於 Descendant Combinator 後代選擇器
- 目標:找包在 div 裡面的 p tag(一層的父子關係),div>p 的效能優於 div p
- 善用 CSS 屬性繼承的特性
非必要的情況,減少使用昂貴的 Attribute
- 昂貴的屬性指的是一些需要瀏覽器進行操作或計算的屬性,它們需要耗費更多的瀏覽器性能。
- 這些都是很常見且很重要的屬性,不是禁用,而是思考是不是有其他替代方案。
- 關於替代方案 (By ChatGPT)
- :hover 替代方案:
- 考慮使用click事件代替hover事件。
- 使用 will-change 屬性。
- :nth-child 屬性替代方案:
- filter 屬性替代方案:
- box-shadow 屬性替代方案:
- 使用適量的陰影,或在不影響性能的情況下考慮使用其他技術,如 SVG 濾鏡。
- border-radius 屬性替代方案:
- 減少 border-radius 的半徑值,以降低性能開銷。
- 使用圖像替代圓角。
- opacity 屬性替代方案:
最佳化 Reflow & Repaint
減少 Reflow
- Reflow 是指瀏覽器為了重新布局而重新計算元素的幾何屬性的過程。
- 改變元素的 margin 或 padding
- 改變元素的 width, height, position 的 left 或 top
- 改變 font-size 或 font-family
- 改變視窗大小
減少 Repaint
- Repaint 是指瀏覽器根據元素的樣式屬性重新繪製元素的過程,而不影響其布局。
- 修改元素的背景色、文字顏色等外觀相關的樣式。
- 使用擴展屬性,例如box-shadow或outline。
- 對元素應用透明度。
- 不是說禁用這些屬性,而是使用前思考是否有別的方式可以完成需求
- 關於替代方案 (By ChatGPT)
-
- Minimize Reflow:
-
- Batch Style Changes for Repaint:
- 將需要改變的樣式集中在一個操作中,以最小化Repaint的發生次數
- 案例:切換主題模式
-
- Avoid Forced Synchronous Layout:
- 改用非強制同步的方式獲取元素的位置信息。
- 案例:獲取元素的位置信息以進行動畫效果。
- getBoundingClientRect() 是用於獲取元素在視窗中位置和尺寸的方法。通常情況下,它是異步執行的,等待瀏覽器完成布局和繪製後才返回。
-
- Defer Changes:
- 將可能觸發Reflow和Repaint的操作延遲到下一個動畫幀。
- 案例:在滾動時實時更新元素的樣式。
如果你的網頁有很糟的 First Contentful Paint (FCP),並且在Lighthouse看到「Eliminate render-blocking resource」(如下圖)…

- 因為瀏覽器得下載與解析 CSS 後才能呈現頁面,所以 CSS 是一個「Render-Blocking-Resource」。
Critical CSS 是一種最佳化網頁性能的技術,主要目標是加速首次載入頁面的速度,特別是針對頁面的上方(above-the-fold)內容,這些內容是用戶首次看到並在滾動之前可見的部分。

above-the-fold content 的範圍並沒有一個明確的界定值,因為每個裝置的大小與螢幕尺寸都不會一樣。
Critical CSS就是渲染首屏的最小CSS集合。
- 找出關鍵 CSS,嵌入到HTML 文檔的<head>中。

Preload
<link rel="preload" />
小結
- 學會撰寫 high performance CSS:有些技術要不要使用得依照實際狀況謹慎考慮,畢竟大多數提升性能的背後都有它們的 trade off 在。
- 建立思維:寫 CSS 時去想一下 reflow repaint 的流程,下手前先思考一下有沒有更好的解法。
13. CSS GPU Acceleration
主軸:如何讓網站達到更順暢的動畫體驗與效能
- Hardware Acceleration 硬體加速 : 瀏覽器會把一些比較複雜的頁面渲染相關任務交給 GPU 處理,而不是全部都靠 CPU 來完成

|
CPU |
GPU |
全名 |
Central Processing Unit 中央處理器 |
Graphics Processing Unit 圖形處理器 |
組成元件 |
控制單元、算術邏輯單元(ALU)、快取及動態隨機存取記憶體(DRAM) |
同左,但設計較為簡易,且數量較多 |
運算模式 |
單控制流單資料流 |
單控制流多資料流 |
比喻 |
一個大學生 |
一群小學生 |
使用情景 |
邏輯複雜(通才型處理器) |
平行計算大批量的重複任務 |
GPU 硬體加速的原理和分層有關
過程:render tree -> 渲染元素-> 圖層-> GPU 渲染-> 瀏覽器複合圖層-> 產生最終的螢幕影像。


- 主執行緒(Main Thread):
- Render Tree 的構建
- 渲染元素:將Render Tree每個節點映射到相應的渲染器。
- 圖層的創建: 根據一些規則,主執行緒可能會將某些渲染器分配到單獨的圖層中。
- 佈局計算(Layout):確定每個渲染器的確切位置和大小。
- 繪製(Paint):繪製每個元素的內容,包括文字、顏色和背景等。
- 合成執行緒(Compositor Thread):
- 圖層的合成:接收主執行緒提供的圖層訊息合成最終的網頁視圖,並利用 GPU 資源進行硬體加速的渲染。
- 動畫處理: 處理滾動、CSS 動畫等動畫效果,確保視覺呈現的平順性。
- 獨立圖層樹的維護
- 瀏覽器複合圖層(Browser Composite Layer):
- 合成請求的生成: 如果有需要,主執行緒會生成合成請求,標記哪些部分的畫面需要重新合成。
- 瀏覽器複合圖層的生成:由主執行緒和合成執行緒之間的協同操作,將合成執行緒生成的圖層和主執行緒生成的其他圖層整合在一起。
- 產生最終的螢幕影像
- 在網頁渲染的過程中,有些元素會因為符合了某些規則,而被提升為獨立的圖層。
- GPU 會運行在獨立的 Process 裡,不會 block 住 Render Engine 的其他工作。
範例
TIPS:
chrome devtools 開啟Rendering 中的Layer borders 查看圖層紋理。
黃色邊框表示該元素有3d 變換,表示放到新的複合層(composited layer)中渲染。
建立獨立圖層
哪些規則能讓瀏覽器主動幫我們建立獨立的圖層呢?(By ChatGPT)
- 3D 變換和透視(3D Transforms and Perspective):
- 例如 : transform: translate3d 或 transform: perspective 屬性。
- 加速屬性(Accelerated Properties):
- 視口外的元素(Offscreen Elements)
- 具有硬體加速屬性的動畫元素(Animating Elements with Hardware Acceleration)
- 遮罩和裁剪(Masking and Clipping)
- 視口內的可滾動元素(Scrollable Elements within the Viewport):
- 例如 : verflow: auto 或 overflow: scroll 屬性的元素。
- Canvas 元素(Canvas Elements)
如何確認瀏覽器有沒有支援硬體加速
如何啟用硬體加速?
有一些 CSS 屬性被歸類於 GPU accelerated properties,也就是被瀏覽器認定為「有機會」被 GPU 加速的屬性:
- transform
- opacity
- filter
如果有些元素不需要用到上述屬性,但是需要觸發硬體加速效果,可以使用一些小技巧來誘導瀏覽器開啟硬體加速。
- 缺點:
- memory 的使用量急遽提升 => 手機的瀏覽器直接 crash
- GPU 渲染會影響字體的抗鋸齒效果 => 文字模糊
- 解決方式:測試結果說話(ex: Chrome DevTools的Performance面板,記錄每個用例的性能指標,如渲染時間、幀率、記憶體使用量等。)
will-change property
- 新的 CSS 屬性:不必依賴 transform hack來開啟硬體加速。
- 讓瀏覽器可以先行準備並「讓瀏覽器選擇」最好的方式來處理這個變動。
- 例如:CSS transform => 螢幕閃爍
使用 will-change 的 Tips
- 不要 will-change 套用在根本不會需有用到的元素
小結
- 分層是 GPU 硬體加速的關鍵,允許瀏覽器僅重繪和重排變化的部分,而不是整個網頁,這對於提高性能和渲染速度至關重要。
- 善用將經常變換的DOM主動提升到獨立的層的規則,那麼在瀏覽器的一幀運行中,就可以減少Layout 和Paint 的時間了。
參考資料
https://dev.to/arikaturika/how-web-browsers-work-the-render-tree-part-7-with-illustrations-24h3
https://ithelp.ithome.com.tw/articles/10273656
https://cloud.tencent.com/developer/article/1906655