實作動畫的方案主要有6種:Javascript直接實作動畫,可伸縮向量圖形(SVG)動畫,CSS transition,CSS3 animation、Canvas動畫、requestAnimationFrame。
<!DOCTYPE html><html><head> <style> .content{width: 100px;height: 100px;background-color: red;} </style></head><body><p class="content"></p><script> var ele=document.getElementsByClassName("content")[0]; var left=0; let timer=setInterval(function () { if(left<window.innerWidth-100){ ele.style.marginLeft=left+'px'; left++; } else { clearInterval(timer); } },16);</script></body></html>
缺點:透過Javascript實作動畫通常會導致頁面頻繁重排重繪,並且很消耗效能。
依照常理來說,改變元素位置會產生重排,為什麼上面圖顯示的全是重繪呢?原因是絕對定位會建立一個新的圖層,而此圖層上只有目前一個元素,所以只會重繪,而不會重排。這也告訴我們,在同一層中,元素數量少的情況下,重排性能對更好,速度會更快。
<!DOCTYPE html><html><head> <style> .content{ width: 100px; height: 100px; background-color: red; transition: all 10s ease-in-out 0s; -webkit-transition: all 10s ease-in-out 0s; margin-left: 0; } .right{ width: 100px; height: 100px; margin-left: 400px; background-color: blue; } </style></head><body><p class="content"></p><script>var timer=setTimeout(function () { var content=document.getElementsByClassName("content")[0]; content.setAttribute('class','right'); },500);</script></body></html>
為什麼 transform 沒有觸發 repaint 呢?簡而言之,transform 動畫由GPU控制,支援硬體加速,並不需要軟體方面的渲染。
硬體加速原理
瀏覽器接收到頁面文件後,會將文件中的標記語言解析為DOM樹。 DOM樹和CSS結合後形成瀏覽器建置頁面的渲染樹。渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個圖層又會被載入到GPU形成渲染紋理,而圖層在GPU中transform 是不會觸發repaint 的,最終這些使用transform 的圖層都會由獨立的合成器流程處理。
<!DOCTYPE html><html><head> <style> .content{ width: 100px; height: 100px; background-color: red; transition: all 10s ease-in-out 0s; -webkit-transition: all 10s ease-in-out 0s; animation: move 4s infinite; margin-left: 0; } @keyframes move { from{ margin-left: 0; } 50%{ margin-left: 400px; } to{ margin-left: 0; } } </style></head><body><p class="content"></p></body></html>
並不是所有的CSS屬性都能觸發GPU的硬體加速(圖層在GPU中屬性改變不會觸發repaint ),實際上只有少數屬性可以,例如下面的這些:
transform
opacity
filter
<!DOCTYPE html><html><head></head><body><canvas id="canvas" width="700" height="500"></canvas><script> var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var left=0; var timer=setInterval(function () { ctx.clearRect(0,0,700,550); ctx.beginPath(); ctx.fillStyle="#f00"; ctx.fillRect(left,0,100,100); ctx.stroke(); if(left>700){ clearInterval(timer); } left+=1; },16);</script></body></html>
<!DOCTYPE html><html><head> <style> p{width: 100px;height: 100px;background-color: red;} </style></head><body><p id="box" width="700" height="500"></p><script> window.requestAnimationFrame=window.requestAnimationFrame|| window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; let element=document.getElementById("box"); let left=0; requestAnimationFrame(step); function step() { if(left<window.innerWidth-200){ left+=1; element.style.marginLeft=left+"px"; requestAnimationFrame(step); } }</script></body></html>
以上是JS動畫實作方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!