首先浏览器会请求页面文件,在互联网中数据是以数据包的形式发送的,其单位是字节(Bytes)。
1.html和css的加载方式
请求得到html数据包 => 将原始字节转换为字符 => 将字符转为Tokens(可以理解为数据结构,包含开始、结束标签和一些属性) => 转换为节点 => 转换为DOM树/css树
html:Bytes => Characters => Tokens => Nodes => DOM
css:Bytes => Characters => Tokens => Nodes => CSSOM
CSS 有一个叫做级联的东西。级联是浏览器确定如何在元素上应用样式的机制
2.页面的渲染
-
浏览器拿到HTML后,从上到下顺序解析文档
-
解析HTML,构建DOM树(这里遇到外链,此时会发起请求)
-
解析CSS,生成CSS规则树
-
合并DOM树和CSS规则,生成render树
-
布局render树(Layout/reflow回流),负责各元素尺寸、位置的计算
-
绘制render树(paint/repaint重回),绘制页面像素信息
-
浏览器会将各层的信息发送给GPU,GPU将各层合成(composite),显示在屏幕
-
这里要特别注意,由于有CSS资源,CSSOM还未构建前,会阻塞js(如果有的话)
-
无论JavaScript是内联还是外链,只要浏览器遇到
script
标记,唤醒JavaScript解析器
,就会进行暂停浏览器解析HTML,并等到CSSOM
构建完毕,才执行js脚本
3.阻塞页面渲染
- css阻塞页面渲染;
- css不会阻塞dom的渲染,但是会和dom树一起生成render树;(所以把css放在前面)
- js会阻塞dom的解析
- js会等到css解析完在执行
4.优化页面加载
-
减少资源请求数量(内联亦或是延迟动态加载)
-
使CSS样式表尽早加载,减少@import的使用,因为需要解析完样式表中所有import的资源才会算CSS资源下载完
-
异步js: JavaScript 会强制浏览器等待 CSSOM 并暂停 DOM 的构建,导致首次渲染的时间延迟
5.页面加载中回流、重绘
layout(布局):根据render tree计算节点的位置和大小;
reflow(回流):1.内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树;2.浏览器为了获得正确的值也会触发回流
paint(绘制):根据计算出来的位置和大小通过GPU渲染到屏幕;
repaint(重绘):节点的只改变一些样式(背景色,边框颜色,文字颜色等);
6.优化reflow、repaint触发次数
-
避免逐个修改节点样式,批量修改
-
可以将需要多次修改的DOM元素设置
display:none
,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘) -
将复杂的节点元素脱离文档流,降低回流成本