关于javascript:浏览器重排回流重绘以及优化方案

3次阅读

共计 1821 个字符,预计需要花费 5 分钟才能阅读完成。

一、什么是重排和重绘

要说清重排 (reflow) 和重绘(repaint),首先要了解排列和绘制,浏览器渲染页面时,在获取完 html、css 资源之后,会大抵通过以下步骤。
(1) html 生成 html 树
(2) css 造成 css 规定
(3) 两者造成一个渲染树
(4) 去文档当中找寻各自的布局地位 —– 排列
(5) 将内容填充到文档上 —– 绘制
【排列】就是计算地位调整布局的过程,而【绘制】就是把它画下来的过程。【重排】也就是除了最开始排列的布局,后续通过一些操作而使得 dom 元素从新找寻地位的过程,【重绘】就是从新绘制内容的过程。

二、什么状况会引发重排和重绘

1、先来说重排,重排和地位的挪动布局的变动无关,次要有以下几种状况会引发重排
(1) 浏览器的窗口发生变化,每放大、放大一次浏览器的窗口,该页面的所有元素都要进行重排重绘
(2) 减少、删除、挪动 dom 元素,更改 dom 元素的宽高内外边距、内容,批改 dom 元素的款式
(3) 进行 dom 元素宽低等属性的查问,因为每查问一次,浏览器都会对所有的元素进行从新计算,以确保计算的值是正确的

2、再来说重绘,重绘次要是元素的外观发生变化,不会从新布局,有以下状况会引发重绘
元素的背景 (background)、文字色彩(color)、边框款式(outline) 发生变化

3、重排和重绘的关系
重绘不肯定须要重排,因为可能只是元素批改文字色彩,不须要从新布局,重排大多数状况都须要重绘,因为重新排列元素之后要绘制到屏幕上。

以下显示重排和重绘的耗时,方块两秒之后右移了 100px

三、为什么要优化

因为重排和重绘不只是对单个的 dom 元素进行操作,而是对整个【图层】进行操作,须要破费工夫,如果频率高,十分的影响性能。

那什么是图层?如下图所示

因为每一次的重排重绘都是操作整个图层,那么咱们能够将须要频繁操作的 dom 元素另外建设一个图层,这样能够尽可能少的触发重排重绘。

那么什么状况能够开启图层?
针对频繁操作的行为,chrome 浏览器主动开启了图层,次要有以下几种状况
1、css 3D 变动的图形 —- transform: translateX(0)
2、html5 中的 <video> 标签
3、canvas 绘图中的节点
4、css 动画的节点 — keyframes animation
5、领有 css 减速属性 — will-change: transform

除此之外,还能够应用以下形式进行优化
1、对元素进行挪动时,应用 transform 代替对元素 top、left、right 的操作,因为 css3 的整个操作是对图层的组合来实现的,所以不会引发重绘重排。

#node{
  // position: relative; 
  transform: translateX(0);
  width: 100px;
  height: 100px;
  background: pink;
}
var node = document.querySelector("#node");
setTimeout(function(){
    //   node.style.left="100px";
   node.style.transform="translateX(100px)";
},2000);

同样是对一个元素两秒后挪动 100px,能够看到比照下图比照

2、将屡次对款式的操作合并成一次
不要一次一次的批改款式,而是事后定义好 class,间接批改 DOM 的 className,这样只会引发一次重排重绘
3、将 dom 离线后批改
如果要对 dom 元素进行屡次操作,首先将 dom 设置为不可见,而后再对 dom 操作,操作实现后再将 dom 元素设置为可见,这样只会有两次重排重绘
4、利用文档碎片 documentFragment
documentFragment 不是实在 dom 树的一部分,它的变动不会触发 dom 树的从新渲染,且不会导致性能等问题,将创立的新元素全副增加到 documentFragment 上,最初让 documentFragment 一起插入到 dom 元素中

const list = ['哈尔的挪动城堡', '千与千寻的神隐', '起风了']
const ul = document.getElementsByTagName("ul")[0]
let fragment = document.createDocumentFragment()
for(let i in list){fragment.appendChild(list[i])
}
ul.appendChild(fragment)
正文完
 0