1. 程式人生 > >我們來看看chrome控制檯動畫的效能

我們來看看chrome控制檯動畫的效能

問題1:我們使用left/top來看看動畫的效能

body {
  padding: 30px;
  text-align: center;
}

.container {
  position: relative;
  min-height: 400px;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}
.ball {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.75);
}
.ball:nth-last-child(1) {
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/splogo.png');
  background-position: center center;
  background-repeat: no-repeat;
}
.ball-running {
  -webkit-animation: run-around 4s infinite;
  animation: run-around 4s infinite;
}
@keyframes run-around {
  0%: {
    top: 0;
    left: 0;
  }
  25% {
    top: 0;
    left: 200px;
  }
  
  50% {
    top: 200px;
    left: 200px;
  }
  
  75% {
    top: 200px;
    left: 0;
  }
}
我們的頁面結構如下:
 <div class="container">
    <div class="ball" id="ball"></div>
</div>
然後我們看看JS程式碼:
var balls = document.getElementById('ball');
balls.classList.add("ball");
balls.classList.add('ball-running');
我們從控制檯來看看動畫的執行效能:

首先我們看到動畫執行的時候一直有一個綠色框,這表示重繪的區域,而且是一直重繪的:


第二步:我們看看這個動畫的時間分佈


我們可以看到頁面重繪的時間是107.3ms,二頁面迴流的時間是186.8ms

第三步:我們看看具體的事件步驟


我們可以看到每次都會重新計算樣式,位置大小等,然後更新每一層的元素的相關資訊,然後合成每一層的內容顯示。這將導致很嚴重的重繪和迴流,對於效能的消耗要大得多。注意:這裡只有一個圖層,就像PS圖層一樣,我們只是會重新繪製圖層中的元素,而不是整個圖層本身,因此圖層本身並沒有變成綠色。

問題2:我們看看使用transform實現的動畫效能

修改CSS樣式如下:

              body {
		  padding: 30px;
		  text-align: center;
		}
		.container {
		  position: relative;
		  min-height: 400px;
		  -webkit-tap-highlight-color: rgba(0,0,0,0);
		}
		.ball {
		  position: absolute;
		  top: 0;
		  left: 0;
		  width: 100px;
		  height: 100px;
		  border-radius: 50%;
		  box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.75);
		}
		.ball:nth-last-child(1) {
		  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/splogo.png');
		  background-position: center center;
		  background-repeat: no-repeat;
		}
		.ball-running {
		  animation: run-around 4s infinite;
		}
		@keyframes run-around {
		  0% {
		    transform: translate(0, 0);
		  }
		  25% {
		    transform: translate(200px, 0);
		  }  
		  50% {
		    transform: translate(200px, 200px);
		  }
		  75% {
		    transform: translate(0, 200px);
		  }
		}
第一步:我們看到瀏覽器為該元素產生了一個獨立的層

第二步:我們看看總時間分佈



可以看到重繪的時間明顯減少

第三步:看看事件的順序


我們看到這裡主要牽涉到樣式計算,然後更新特定層的元素,最後再合成就可以了,明顯沒有了前面的重繪和迴流操作。注意:因為這裡是transform屬性的改變,如果是改變left/top值,那個這個圖層還是會發生迴流和重繪操作的。

瀏覽器接收到頁面文件後,會將文件中的標記語言解析為DOM樹。DOM樹和CSS結合後形成瀏覽器構建頁面的渲染樹。渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個圖層又會被載入到GPU形成渲染紋理,而圖層在GPU中 transform 是不會觸發 repaint 的(只是重新計算元素的樣式,然後根據計算的樣式更新特定層的元素,然後把更新後的層和其他層合成起來,這個過程中是沒有repaint的),這一點非常類似3D繪圖功能,最終這些使用 transform 的圖層都會由獨立的合成器程序進行處理。

注意:因為上面我們使用的是2D變化,而不是3D變換。3D 和 2D transform 的區別就在於,瀏覽器在頁面渲染前為3D動畫建立獨立的複合圖層,而在執行期間為2D動畫建立。動畫開始時,生成新的複合圖層並載入為GPU的紋理用於初始化 repaint。然後由GPU的複合器操縱整個動畫的執行。最後當動畫結束時,再次執行 repaint 操作刪除複合圖層。所以,上面的例子在開始和結束的時候會有兩次repaint操作。

問題2:不要弄混淆,即使單獨建立了一個圖層,如果變動了重繪和重排的指標,也是會迴流和重排的

例子的程式碼如下:

     .box{
       	  width:100px;
       	  height:100px;
       	  background-color: #ccc;
       	  position:absolute;
       	  top:0;
       	  left:0;
       	  transition:left 5s linear;
       	  transform: translateZ(0);
       	  /*這時候雖然給我們的box元素放在一個獨立的層當中,但是我們依然修改了他的left屬性,所以他肯定會重繪迴流,除非我們修改為transform屬性和opacity*/
       }
       .hv{
       	 left:400px;
       }
JS程式碼如下:
    window.onload=function(){
       	 	var box=document.querySelector('.box');
       	 	box.classList.add('hv');
       	 }
DOM結構如下:
 <div class="box"></div>
這時候我們通過了transform:translateZ為這個元素建立了一個獨立的圖層,但是我們的transition依然是通過left來完成的,這時候也是會發生迴流,重繪,合成操作的。但是這時候的迴流,重繪,合成操作都是在該圖層中進行的,而不會影響其他的圖層。



我們把上面的動畫使用transform來完成

 .box1{
       	  width:100px;
       	  height:100px;
       	  background-color: #ccc;
       	  position:absolute;
       	  top:0;
       	  left:0;
          transition:transform 5s;
          -webkit-transition: -webkit-transform 2s;
          -webkit-backface-visibility:hidden;
       	  transform: translate3d(0,0,0);
       	  -webkit-perspective:1000;  
       }
       .hv1{
       	  transform: translate3d(200px,0,0);
       }
修改CSS屬性如上,我們看看結果如何


這時候我們看到已經沒有前面說的重繪和迴流了,這就是transform動畫的優秀之處。使用tranforms來實現移動效果的元素將會被正常繪製,同時不會觸發對其他元素的繪製。這種處理方式和思想跟影象處理軟體(比如Sketch/GIMP/Photoshop)是一致的,它們都是可以在影象中的某個單個圖層上做操作,最後合併所有圖層得到最終的影象。摘抄自簡化繪製的複雜度、減小繪製區域