圖層 & 重排 & 重繪

圖層javascript

瀏覽器在渲染一個頁面時,會將頁面分爲不少個圖層,圖層有大有小,每一個圖層上有一個或多個節點css

渲染 DOM 時 瀏覽器所作的:html

  • 獲取 DOM 後分割爲多個圖層
  • 對每一個圖層的節點計算樣式結果 (Recalculate style--樣式重計算)
  • 爲每一個節點生成圖形和位置 (Layout--重排,迴流)
  • 將每一個節點繪製填充到圖層位圖中 (Paint--重繪)
  • 圖層做爲紋理上傳至 GPU
  • 符合多個圖層到頁面上生成最終屏幕圖像 (Composite Layers--圖層重組)

圖層建立條件vue

Chrome 中知足 如下任意狀況 就會建立圖層:java

擁有 3D 變換的 css 屬性 transformcss3

加速視頻解碼的 <video> 節點canvas

 <canvas> 且瀏覽器硬件加速瀏覽器

css3 動畫節點 animationide

擁有 css 加速屬性的元素 (will-change: transform; 記得取消爲 auto )佈局

重繪(Repaint)

指的是 一個元素外觀的改變 而觸發的瀏覽器行爲

例如改變 outline、背景色等屬性。瀏覽器會根據元素的新屬性從新繪製

瀏覽器會根據元素的新屬性對元素進行從新繪製,使元素呈現新的外觀

重繪 不會伴隨 重排,可是 重排 必定會 重繪

以圖層爲單位,若是圖層中某個元素須要重繪,那麼整個圖層都須要重繪

重排(Reflow)

渲染對象 在建立完成並添加到渲染樹時,並不包含位置和大小信息。計算這些值,稱之爲 重排

resize 時、修改網頁默認字體時,操做 DOM 節點時,修改 css 樣式時

獲取某些屬性時(width、height... ...)

優化方案:

減小 計算須要被加載到節點上的樣式結果(Recalculate style--樣式重計算)

減小 爲每一個節點生成圖形和位置(Layout--迴流和重佈局)

減小 將每一個節點填充到圖層中(Paint Setup和Paint--重繪)

減小 組合圖層到頁面上(Composite Layers--圖層重組)

元素位置的改變 使用 transform

使用 opacity + will-change: transform; 代替 visibility        單獨使用 opacity 會重排、重繪; 結合圖層後只會發生重繪

不使用  table 佈局

將屢次 css 操做,集合成一次 css 操做

多使用 class 修改樣式

使用 display: none; 離線 DOM 元素,在一頓 css 操做之後,再 display: block 顯示;

(vue 底層就是使用 documentFragment 來優化的)使用文檔碎片 documentFragment 

不要把某些 DOM 節點的屬性 在循環裏做爲變量使用

給要動的元素,單獨開一個圖層

總結:

Reflow 的成本比 Repaint 的成本高得多的多。DOM Tree 裏的每一個結點都會有 reflow 方法

一個結點的 reflow 頗有可能致使子結點,甚至父點以及同級結點的 reflow。

在一些高性能的電腦上也許還沒什麼,可是若是 reflow 發生在手機上,那麼這個過程是很是痛苦和耗電的。

 

requestAnimationFrame

  • <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8" />
            <title>requestAnimationFrame</title>
            
            <style rel="stylesheet" type="text/css">
                body {
                    width: 100%;
                    color: #000;
                    background: #96b377;
                    font: 14px Helvetica, Arial, sans-serif;
                }
    
                a {
                    text-decoration: none;
                    color: green;
                }
    
                #test_box {
                    width: 100px;
                    height: 100px;
                    background-color: red;
                }
            <style/>
        </head>
        
        <body>
            
            <div id="test_box" class="clearfix"></div>
            
            <!-- javascript 代碼 -->
            <script type="text/javascript" src="./js/index.js">
                window.addEventListener("DOMContentLoaded", function(){
                    var testBox = document.getElementById("test_box");
                    
                    /**** requestAnimationFrame ****/
                    var element = testBox;
                    element.style.position = 'absolute';
                    
                    var start = null;
                    var offset = 0;
                    var speed = 5;
                    function step(timestamp) {
                        if (!start){
                            start = timestamp;
                        };
                        var progress = (timestamp - start)/speed;
                        endPos = 500;
                        
                        // 元素不斷向左移,最大不超過200像素
                        offset = progress;
                        if(parseInt(progress/endPos)%2 == 0){
                            offset = progress%endPos;
                        }else{
                            offset = endPos - progress%endPos;
                        };
                        
                        element.style.left = offset%endPos + 'px';
                        
                        // 若是距離第一次執行不超過 2000 毫秒,
                        // 就繼續執行動畫
                        //if (progress < 2000) {
                            window.requestAnimationFrame(step);
                        //};
                    };
                    
                    window.requestAnimationFrame(step);
                }, false);
            </script>
        </body>
    </html>
相關文章
相關標籤/搜索