.jpg)
# 浏览器渲染页面的机制和原理

- 解析HTML,生成DOM树,解析CSS,生成CSSOM树
- 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
- Layout(回流): 根据生成的渲染树,计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流
- Painting(重绘): 根据渲染树以及回流得到的几何信息,得到节点的绝对像素
- Display:将像素发送给GPU,展示在页面上

# DOM的重绘和回流 Repaint & Reflow
重绘:元素样式的改变(但宽高、大小、位置等不变)
如 outline, visibility, color、background-color等回流:元素的大小或者位置发生了变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新计算布局和渲染- 如添加或删除可见的DOM元素 ;
- 元素的位置发生变化;
- 元素的尺寸发生变化;
- 内容发生变化(比如文本变化或图片被另一个不同尺寸的图片所替代);
- 页面一开始渲染的时候(这个无法避免);
- 因为回流是根据视口的大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化也会引发回流
注意:回流一定会触发重绘,而重绘不一定会回流
# 避免DOM的回流
- 放弃传统操作dom的时代,基于vue/react开始数据影响视图模式 mvvm / mvc / virtual dom / dom diff ....
- 分离读写操作 (现代的浏览器都有渲染队列的机制)offsetTop、offsetLeft、offsetWidth、offsetHeight、clientTop、clientLeft、clientWidth、clientHeight scrollTop、scrollLeft、scrollWidth、scrollHeight、getComputedStyle、currentStyle....会刷新渲染队列
=>渲染队列机制导致引发一次回流
=>没有渲染队列机制的话写width的时候触发一下次,写height的时候也会触发一次
navBox.style.width = '100px';
navBox.style.height = '100px';
=>触发两次
navBox.style.width = '100px'; 写
console.log(navBox.clientWidth);读
navBox.style.height = '100px';
=>所以需要把读写分开(读写分离)
navBox.style.width = '100px';
navBox.style.height = '100px';
console.log(navBox.clientWidth);
- 样式集中改变
div.style.cssText = 'width:20px;height:20px;'
或
div.className = 'box';
4. 缓存布局信息
div.style.left = div.offsetLeft + 1 + 'px';
//相当于读写没分离 div.style.left是写样式 需要读取div.offsetLeft
div.style.top = div.offsetTop + 1 + 'px';
=>改为
var curLeft = div.offsetLeft; var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px';
- 元素批量修改
用于增加元素的时候
=>10次回流
for (let i = 0; i < 10; i++) {
let span = document.createElement('span');
navBox.appendChild(span);
}
第一种方式
let frag = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
let span = document.createElement('span');
frag.appendChild(span);
}
navBox.appendChild(frag);// 一次回流
第二种方式
let str = ``;
for (let i = 0; i < 10; i++) {
str += `<span></span>`;
}
navBox.innerHTML = str;
- 动画效果应用到position属性为absolute或fixed的元素上(脱离文档流 )
- CSS3硬件加速(GPU加速)
比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘;transform \ opacity \ filters ...这些属性会触发硬件加速,不会引发回流和重绘......可能会引发的坑:过多使用会占用大量内存,性能消耗严重、有时候会导致字体模糊等 - 每次1像素移动一个动画,但是如果此动画使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。每次移动3像素可能看起来平滑度低了,但它不会导致CPU在较慢的机器中抖动
- 避免table布局和使用css的javascript表达式