剛好在最近工作上有遇到這個問題,就趁這個機會來討論 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) 整個畫面或部分畫面,從而增加效能負擔,尤其在複雜的網頁中,這可能會導致畫面卡頓或掉幀。
這要從瀏覽器如渲染出一個網頁開始:
在主執行緒中,DOM Tree 和 CSSOM Tree 會合併成 Render Tree。
Layout: 在主執行緒中,瀏覽器根據 Render Tree 生成 Layout Tree,計算每個元素的位置和大小。
Paint: 在主執行緒中,瀏覽器根據 Layout Tree 進行繪製。
合成 Compositing:在 Compositor thread 和 Raster thread 中,瀏覽器將繪製好的圖層進行合成。
無論是 Reflow 或 Repaint ,當觸發了上方渲染的某一個階段後,後續的階段也都會跟著被觸發。
所以回到這個問題的本質,當使用 absolute
絕對定位移動元素時,會觸發 reflow,這時候瀏覽器會重新計算元素的位置然後產生新的 Layout Tree,接著進行 Repaint 和 Compositing。
但是使用 translate()
移動元素時,不會觸發 reflow 和 repaint,只會觸發合成階段。此外還有另外一個好處是合成階段不是在主執行緒中進行的,這樣就不會影響到主執行緒的效能,因此使用 translate()
移動元素的效果比 absolute
絕對定位更可以縮短瀏覽器繪製的時間,還能讓動畫在 GPU 上進行處理讓動畫更加流暢。