居中為什麼用transform,而不是margin top/left

柳菁發表於2019-01-07

首先。我們瞭解下transform是幹嘛的。

在MDN中的官方解釋:CSStransform屬性允許你旋轉,縮放,傾斜或平移給定元素。這是通過修改CSS視覺格式化模型的座標空間來實現的。簡言之,transform可以操作一些動畫、位移效果。

margin top/left,我們應該很熟悉,用得比較多。

那為什麼說,居中顯示,CSS3標準的transform更勝一籌呢?我們主要還是從瀏覽器渲染的效能方面考慮。

1. 瀏覽器渲染過程

我們知道,瀏覽器中有JS引擎和渲染引擎,對於HTML頁面的渲染就靠渲染引擎來完成。下面是chrome瀏覽器頁面渲染的整體過程圖:

Chrome渲æè¿ç¨

(www.w3cplus.com/animation/a… © w3cplus.com)

從上面的流程圖中不難看出,Chrome渲染主要包括Parse Html、Recalculate Style、Layout、Paint、Image Decode、Image Resize和Composite Layers等。相對應的中文表述就是:html解析、查詢並計算樣式、排布、繪製、圖片解碼、圖片大小設定、合併圖層並輸出頁面到螢幕。瀏覽器最終渲染出來的頁面,跟Photoshop有點類似,是由多個圖層合併而來。

2. transform的原理:

transform是通過建立一個RenderLayers合成層,擁有獨立的GraphicsLayers。每一個GraphicsLayers都有一個Graphics Context,其對應的RenderLayers會paint進Graphics Context中。合成器(Compositor)最終會負責將由Graphics Context輸出的點陣圖合併成最終螢幕展示的圖案。

滿足如下條件的RenderLayers,會被認為是一個獨立的合成層:

  • 有3D或者perspective transform的CSS屬性的層
  • video元素的層
  • canvas元素的層
  • flash
  • 對opacity和transform應用了CSS動畫的層
  • 使用了CSS濾鏡(filters)的層
  • 有合成層後代的層
  • 同合成層重疊,且在該合成層上面(z-index)渲染的層

如果RenderLayer是一個合成層,那麼它有屬於它自己的單獨的GraphicsLayer,否則它和它的最近的擁有GraphicsLayer的父layer共用一個GraphicsLayer。

由此可見,transform發生在Composite Layer這一步,它所引起的paint也只是發生在單獨的GraphicsLayer中,並不會引起整個頁面的迴流重繪。

3. GPU

我們經常會聽到GPU會加速渲染,那GPU在這裡又扮演什麼角色呢?

前面說到,合成器會負責將層合成繪製為最終的螢幕畫面。在硬體加速體系結構,合成由GPU負責。在chrome瀏覽器多程式模型中,有一個專門的程式來負責傳遞Render程式的命令,即GPU程式。Render程式和GPU程式是通過共享記憶體傳遞的。

Render程式可以快速 的將命令發給命令緩衝區,並且返回到CPU密集的render活動中,留給GPU程式去處理這些命令。我們可以充分利用多核心機器上的GPU程式和CPU程式。這也是為什麼GPU會加速渲染,使transform渲染速度更快的又一原因。

4. margin top/left

marign:外邊距,定義元素周圍的空間;簡言之,可以改變元素的位移。在瀏覽器頁面渲染的時候,margin可以控制元素的位置,也就是說,改變margin,就會改變render tree的結構,必定會引起頁面layout迴流和repaint重繪。

因此,從瀏覽器效能考慮,transform會比margin更省時間。

但是,transform真的處處適用嗎?

5. transform的侷限性

上面提到,transform實際上也是用到了GPU加速,也就是說佔用了記憶體。由此可見建立GraphicsLayer,雖然潔身了layout,paint階段,但Layer建立的越多,佔用記憶體就會越大,而過多的渲染開銷會超過效能的改善。

因此,當且僅當需要的時候,才會為元素建立渲染層。


相關文章