内容提要
浏览器渲染页面的流程包括html解析、样式计算、布局、分层、绘制、分块、光栅化和绘画等多个阶段。解析过程中,css不会阻塞html解析,而js会阻塞html解析。渲染完成后得到dom树和cssom树,然后进行样式计算、布局和分层。主线程为每个层生成绘制指令集,合成线程进行分块和光栅化,最后生成位图并绘画。reflow是重新计算布局树,repaint是重新计算绘制指令。transform的效率高因为它只影响渲染流程的最后一个阶段。
延伸解读
CSS与JS阻塞解析的差异
文章指出,CSS解析不会阻塞HTML解析,因为浏览器会启动预解析线程提前下载CSS,主线程遇到link时不会等待,继续解析后续HTML。而JS会阻塞HTML解析,因为JS执行可能修改DOM树,必须暂停解析。这一差异对页面性能优化有实际意义:将CSS放在头部、JS放在底部或使用async/defer,可以减少阻塞。
DOM树与布局树并非一一对应
布局阶段会遍历DOM树计算几何信息,但DOM树和布局树并非一一对应。例如display:none的节点没有几何信息,不会生成到布局树;伪元素虽然不在DOM中,但拥有几何信息,会生成到布局树。匿名行盒、匿名块盒也会导致两者无法一一对应。理解这一点有助于调试布局问题。
transform高效的本质原因
transform之所以高效,是因为它既不影响布局也不影响绘制指令,只影响渲染流程最后的draw阶段。draw阶段在合成线程中执行,与渲染主线程无关。因此transform的变化几乎不会影响主线程,主线程忙碌也不会影响transform。同理,滚动条滚动也属于draw阶段,所以主线程卡住时页面滚动仍可能流畅。
reflow与repaint的关系
reflow本质是重新计算布局树,当操作影响布局树时触发;repaint本质是重新计算绘制指令,当改动可见样式时触发。由于元素的布局信息也属于可见样式,所以reflow一定会引发repaint。浏览器会合并连续的布局操作,在JS代码执行完成后统一计算,因此改动属性造成的reflow是异步完成的。但获取布局属性时,浏览器会立即reflow以返回最新信息。
Q&A
浏览器渲染页面的主要阶段有哪些?
浏览器渲染页面的主要阶段包括html解析、样式计算、布局、分层、绘制、分块、光栅化和绘画。
为什么CSS解析不会阻塞HTML解析?
因为浏览器在解析HTML时,会启动预解析线程下载外部CSS文件,CSS解析在预解析线程中进行,不会影响HTML的解析。
JavaScript如何影响HTML解析?
JavaScript会阻塞HTML解析,因为主线程在遇到script标签时会暂停HTML解析,等待JS文件下载和执行完成后才能继续。
什么是reflow和repaint,它们有什么区别?
Reflow是重新计算布局树,而repaint是重新计算绘制指令。Reflow通常在布局信息改变时触发,而repaint在可见样式改变时触发。
transform为什么被认为效率高?
因为transform只影响渲染流程的最后一个绘制阶段,不会影响布局和绘制指令,因此其变化不会阻塞主线程。
浏览器如何处理分层以提高渲染效率?
浏览器通过对布局树进行分层,将每个层的改变限制在该层内,从而提高后续处理的效率。