為什麼實作 CSS 動畫位移效果使用 translate()
比 absolute
絕對定位更好?
剛好在最近工作上有遇到這個問題,在這裡我們會討論到 translate()
和 absolute
的差異,以及為什麼我們應該使用 translate()
來移動元素。
translate()
的優勢
translate()
是 CSS transform
的一個屬性,用來移動元素的位置。它是一個 2D 或 3D 的函數,可以在 x, y, z 軸上移動元素。
.element {
position: relative;
transform: translate(100px, 100px);
}
當使用 translate()
移動元素的時候,元素仍然保持在原本的位置,只是視覺上移動了,瀏覽器不會重新計算元素的佈局,也就是說,不會觸發 reflow
。取而代之的是,translate()
只會觸發瀏覽器的 合成階段(compositing),這是在 GPU 而非主執行緒中執行的操作,因此效能更佳,並能產生流暢的動畫效果。
absolute
絕對定位的問題
絕對定位會將元素超脫原來的頁面流,並且會根據最近的父元素或是 body
來定位。
.element {
position: absolute;
top: 100px;
left: 100px;
}
使用 absolute
絕對定位該元素然後透過 top
、 left
、 bottom
、right
來移動元素,但是當元素被移動後會觸發 reflow,這樣會造成效能問題,這個過程會導致瀏覽器重新繪製 (repaint) 整個畫面或部分畫面,從而增加效能負擔,尤其在複雜的網頁中,這可能會導致畫面卡頓或掉幀。
瀏覽器的渲染過程
這要從瀏覽器如渲染出一個網頁開始:
(一)、解析階段
- 瀏覽器會解析 HTML 並建立 DOM Tree
- 瀏覽器會解析 CSS Link tag 並建立 CSSOM Tree
(二)、Render 階段
-
在主執行緒中,DOM Tree 和 CSSOM Tree 會合併成 Render Tree。
-
Layout: 在主執行緒中,瀏覽器根據 Render Tree 生成 Layout Tree,計算每個元素的位置和大小。
- 這個過程瀏覽器會將頁面進行分層產生 Layer tree,每一層都是一個獨立的圖層。
- 在這個階段瀏覽器會計算每個圖層的位置和大小,產生一個繪製的指令與塗層疊加的順序。
- 最終這些圖層疊加在一起會形成頁面。
- Reflow 回流:當元素的幾何位置和大小發生變化時,瀏覽器會重新計算 Layout Tree中的元素物理屬性,這個過程稱為 Reflow,例如: height、padding、position...等。
-
Paint: 在主執行緒中,瀏覽器根據 Layout Tree 進行繪製。
- Repaint 重繪:當元素的外觀發生變化時,瀏覽器會重新繪製元素,這個過程稱為 Repaint,例如: color、background-color...等。
-
合成 Compositing:在 Compositor thread 和 Raster thread 中,瀏覽器將繪製好的圖層進行合成。
- 各個 Layer 圖層會進行柵格化 rasterize,將圖層轉換成 Pixel 顯示在螢幕上。
- 在 Compositor thread 將這些經過柵格化的圖層進行合成,將這些圖層合成一個整體的畫面。
- Compositor thread 會將 layer 切成一個個的 tile,然後將這些 tile 送到 Raster thread,將tile 進行柵格化後存到瀏覽器的 GPU 。
- Compositor thread 根據 draw quads 資訊產生 Compositor frame,然後將這些 Compositor frame 送到 browser 階段 。
(三) Browser 階段
- 瀏覽器將 Compositor frame 送到 GPU 。
- 瀏覽器將渲染好的畫面顯示在螢幕上。
無論是 Reflow 或 Repaint ,當觸發了上方渲染的某一個階段後,後續的階段也都會跟著被觸發。
總結
所以回到這個問題的本質,當使用 absolute
絕對定位移動元素時,會觸發 reflow,這時候瀏覽器會重新計算元素的位置然後產生新的 Layout Tree,接著進行 Repaint 和 Compositing。
但是使用 translate()
移動元素時,不會觸發 reflow 和 repaint,只會觸發合成階段。此外還有另外一個好處是合成階段不是在主執行緒中進行的,這樣就不會影響到主執行緒的效能,因此使用 translate()
移動元素的效果比 absolute
絕對定位更可以縮短瀏覽器繪製的時間,還能讓動畫在 GPU 上進行處理讓動畫更加流暢。