关于浏览器的页面渲染
关于浏览器渲染
先来看一张webkit引擎的大致渲染流程:
页面渲染可分为下面几个步骤:
- 处理HTML标记并构建DOM树
- 处理CSS标记并构件CSSOM树
- 将DOM与CSSOM树合并成一个渲染树
- 根据渲染树来布局,计算每个节点的确切大小和位置
- 将各节点绘制到屏幕上
关于浏览器渲染,一个重要概念就是关键渲染路径:
关键渲染路径 是指浏览器从最初接收请求来的HTML、CSS、javascript等资源,然后解析、构建树、渲染布局、绘制,最后呈现给客户能看到的界面这整个过程。
阻塞渲染:
html的解析遇到script标签会停止DOM树的解析并开始下载执行js。因为js是会阻塞html解析的,是阻塞资源。其原因在于js可能会改变html现有结构。例如有的节点是用js动态构建的,在这种情况下就会停止dom树的构建开始下载解析js。脚本在文档的何处插入,就在何处执行。当 HTML 解析器遇到一个 script 标记时,它会暂停构建 DOM,将控制权移交给 JavaScript 引擎;等 JavaScript 引擎运行完毕,浏览器会从中断的地方恢复 DOM 构建。而因此就会推迟页面首绘的时间。可以在首绘不需要js的情况下用async和defer实现异步加载。这样js就不会阻塞html的解析了。
css的加载不会导致DOM解析和构建,但是会影响到js脚本的执行;因为js脚本不仅可以读取修改到dom,也可以读取修改到cssom。故在js脚本执行前,browser必须保证到css文件完全加载并解析完成,即cssom树完全构建好。这就导致了js执行的延迟,也因此导致html解析和渲染延迟。 (这就是css阻塞js执行,阻塞渲染的根本原因) 所以在在引入顺序上,一般css资源的引入要先于js脚本的引入。
重绘和重排:
重绘 repaint:屏幕的一部分重画,不影响整体布局,比如某个CSS的背景色变了,但元素的几何尺寸和位置不变。
重排 reflow:意味着元素的几何信息变了,需要重新验证并计算渲染树。是渲染树的一部分或全部发生了变化。 有以下这些情况可能触发:
- DOM操作(对元素的增删改,顺序变化等)
- CSS属性的更改或重新计算
- 增删样式表的内容
- 修改class属性
- 浏览器窗口变化(滚动或缩放)
- 伪类样式激活(:hover等)
重绘和重排需要重新计算整个渲染树,比较耗时;因此关于页面优化很多许多本质上都是为了减少重绘和重排的次数。
注意: display:none 会触发 reflow,visibility: hidden属性并不算是不可见属性,它的语义是隐藏元素,但元素仍然占据着布局空间,它会被渲染成一个空框,所以visibility:hidden 只会触发 repaint。