图层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>