浏览器渲染原理、回流、重绘
渲染流程
读取HTML --> 解析HTML --> 生成DOM树 --> 生成渲染树(计算CSS属性) -->布局/回流(reflow) -->重绘(repaint)
一、解析HTML
- Q: 什么叫渲染?
- A: 可以把浏览器看作一个画布,页面就是一张图片。浏览器通过像素点将这张图片画出来的过程就叫渲染。
- Q: 解析的是什么?
- A: 解析的是HTML的源代码
- Q: 获取HTML源代码的方式?
- A: ①从网络获取;②从本地文件获取。
- Q: 如何解析?
- A:
- 1.从上到下逐行解析源代码。
- 2.读取到CSS或JS,会停止解析(阻塞)HTML,从而先去解析CSS或执行JS。解析CSS或JS执行完成后就继续解析HTML。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"> // 解析
<meta http-equiv="X-UA-Compatible" content="IE=dege" > // 解析
<link rel="stylesheet" href="./css/index.css"> // 解析到这一步先暂停HTML解析,先去解析CSS
...
</head>
<body>
<h1>hello</h1> // 解析
<script src="./js/index.js" ></script> // 解析到这一步先暂停HTML解析,先去执行JS
<h1>world!</h1> // 解析
...
</body>
</html>
二、生成DOM树
浏览器会一边解析HTML一边生成页面DOM树
DOMContentLoaded事件与window.load事件
- 1.当DOM树全部生成完毕之后就会触发
DOMContentLoaded
事件。该事件不能通过on来注册
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM树全部生成完成")
// 如果想第一时间拿到某一个元素DOM或靠前的元素DOM可以在此处理。此处代码可放到<head>内的<script>中
})
- 2.当页面中的所有外部资源(图片、视频、音频等)全部加载完毕后,会触发
load
事件
window.onload = function() {
console.log("所有的资源都已经加载完毕")
}
// 或
document.addEventListener("onload", function() {
console.log("所有的资源都已经加载完毕")
})
load事件相较于DOMContentLoaded事件较靠后,load事件可以针对单个外部资源使用,资源加载完成后触发。
<img
id="img"
src="http://img.com"
alt=""
/>
<script>
const img = document.getElementById('img')
img.onload = function() {
console.log('图片资源加载完成!')
}
</script>
三、生成渲染树(计算CSS属性)
浏览器会一边生成DOM树时就一边计算DOM树中每个节点的样式规则,CSS属性的计算就发生在这一个步骤
四、布局/回流(reflow)
指浏览器一边生成渲染树的时候就一边计算每个元素最终的尺寸和位置,页面中所有元素的位置和尺寸确定下来之后就准备渲染。 这个步骤会在运行过程中不断地重复和重新排列(回流也叫重排),以下操作会导致回流
- 获取页面中元素的尺寸和位置
- 直接或间接改变元素的尺寸和位置。
reflow比较耗时,浏览器为了提升性能会对JS中连续导致reflow的代码把relow的时间延迟到结束进行。但是,如果在此过程中遇到了读取元素尺寸和位置的代码,浏览器就会被迫强制立即reflow
dom.style.width = '100px' // 不回流
dom.style.height = '200px' // 不回流
dom.style.left = '10px' // 不回流
dom.style.right = '100px' // 回流 浏览器为了提升性能延迟到结束才进行回流
dom.style.width = '100px' // 不回流
dom.style.height = '200px' // 不回流
dom.clientWidht // 回流 获取或改变元素尺寸浏览器被迫立即回流
dom.style.left = '10px' // 不回流
dom.style.right = '100px' // 回流
五、重绘(repaint)
浏览器会一边reflow,一边生成对应的图形绘制到页面 同样,重绘也会不断地重复,以下操作会导致重绘
- 所有会导致回流(reflow)的代码,均会导致重绘
- 改变背景颜色
- 改变字体颜色
- 圆角边框
- 改变背景图
...
绘制过程是靠GPU完成的,速度很快。所以,相较于reflow的代码,仅仅会导致repaint的代码效率会高很多。这也是为什么CSS3动画比JS动画效率高的原因之一。
注:
1.这就是为什么需要将CSS放到页面的开头,需要尽快的解析页面样式让用户看到,同时也避免先出现内容而后又改变样式造成页面闪烁。
2.将JS写最后也是为了防止阻塞从而让页面尽快呈现给用户,同时也能保证JS的执行在DOM元素生成之后,从而保证与获取DOM元素的交互正常。
3.开发中应当减少或优化频繁获取和改变元素尺寸,因为会引起回流,非常耗时。