概念:
- 渲染:画页面
渲染过程:
- 解析html
- 生成DOM树(1、2两步同时进行)
- 生成渲染树
- 重排reflow
- 重绘repaint
解析html文件
- 文件从哪里拿?本地或服务器上
- 从上至下,一行一行读取、解析
- 遇到css和js文件,停止解析html(阻塞),进而解析css、js
- 遇到图片、音频、视频不会阻塞
- css文件放头部,是为了让用户优先看到好看的页面,不会看到空白的、丑陋的页面;js放尾部,是因为用户不着急交互
生成DOM树
- html解析完成,立即触发DOMContentLoaded事件
js
document.addEventListener("DOMContentLoaded",(event)=>{
})
onDOMContentLoaded = (event)=>{}
- 所有资源加载完成(包括样式、图片等资源),会触发load事件
js
window.addEventListener('load',(event)=>{
})
window.onLoad = (event)=>{}
// 也可针对单个资源加载完成触发
let img1 = document.querySelector('#img1')
img.onLoad = (event)=>{
console.log('图片加载完成')
}
DOMContentLoaded事件和load事件的区别:
**** | 触发条件 | 注册在哪里 |
---|---|---|
DOMContentLoaded事件 | html解析完成 | document上 |
load事件 | 所有资源加载完成(包括图片、样式表) | window上 |

生成渲染树
浏览器一边生成DOM树,一边计算DOM树中每个节点的样式规则,最终形成渲染树
css属性的计算过程,发生在这一步骤。先看声明值,再层叠、再冲突、再使用继承值、再使用默认值

布局layout/重排reflow
这一步浏览器一边生成渲染树,一边计算出每个元素最终的位置和尺寸。位置尺寸包含窗口有多大、滚动条在哪个位置、元素显示在窗口哪个位置。
完成后,页面中所有元素的位置和尺寸就确定下来了,即将被渲染到页面。
为什么叫重排?因为这个步骤会反复执行。
这个步骤会在页面之后的运行中不断的重复,下面的js操作均会导致reflow:
- 获取元素位置和尺寸
js
window.screenLeft
- 直接或间接改变元素的位置和尺寸
js
dom.style.width = '100px'
重排非常耗时,浏览器为了提升性能,做了一些处理,最常见的处理是这样的,对js连续导致reflow的代码,会把reflow的时间延后,看下面的例子:
js
dom.style.width = '100px'
dom.style.height = '200px'
dom.style.left = '10px'
dom.style.top = '10px'
每一次改变元素的位置都会导致重排,按理说会导致四次,但是重排非常耗时,这样做没有必要,浏览器会这样做:

代码运行完,页面不变,最后reflow一次
但是,如果在代码中夹杂了读取高度,会导致强行reflow,比如:
js
dom.style.width = '100px'
dom.style.height = '200px'
dom.clientHeight; // 读取高度,会导致强行reflow
dom.style.left = '10px'
dom.style.top = '10px'

这段代码会重排两次。
因此:对于我们开发而言,读取宽高、尺寸时,能不频繁读取就不频繁读取。
重绘repaint
浏览器一边reflow,一边生成对应的图形绘制到页面,绘制的过程称为repaint。
为什么叫重绘?还是跟reflow一样,这个步骤会反复执行。
绘制的过程是靠GPU完成的,速度非常快。因此,相对于导致reflow的代码,不触发reflow的代码,仅触发re'paint的代码效率会更高。
比如说,不涉及尺寸和位置的代码,仅影响元素外观的代码都不会导致reflow,仅导致repaint:
- 改变背景颜色
- 改变字体颜色
- 圆角边框
- 背景图
思考:为什么css3的动画比js动画效率高?
比如:要实现每隔1秒改变元素left值
js
setInterval(()=>{
div.style.left = 'xxx'
},1000)
css
div
{
animation: 3s ease-in 1s infinite reverse both running slidein;
}
用js每一次改变left的值会导致reflow,因为元素的位置变了。但用css3不会导致重排,效率更高