圖層javascript
瀏覽器在渲染一個頁面時,會將頁面分爲不少個圖層,圖層有大有小,每一個圖層上有一個或多個節點css
渲染 DOM 時 瀏覽器所作的:html
圖層建立條件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>