浏览器渲染机制


浏览器渲染机制

不同的浏览器内核不同,渲染过程中有的细节也不一样,以webkit主流程为例:

浏览器解析渲染机制

浏览器解析渲染页面大致过程:

1、DOM Tree:浏览器向服务器发送http请求,服务器响应http请求并发送文档给浏览器,浏览器解析HTML构建DOM树。

其中HTML Parser就起到了将HTML标记解析成DOM Tree的作用,HTML Parser将文本的HTML文档,提炼出关键信息,嵌套层级的树形结构,便于计算拓展;这其中也有很多的规则和操作,比如容错机制,识别特殊标签<br></br>

2、CSSOM浏览器解析CSS构建CSSOM树。

CSS Parser将很多个CSS文件中的样式合并解析出具有树形结构Style Rules,也叫做CSSOM

其中还有一个细节是浏览器解析文档:当遇到<script>标签的时候会停止解析文档,立即解析脚本,将脚本中改变DOM和CSS的地方分别解析出来,追加到DOM Tree和CSSOM上

3、Render TreeDOM树和CSSOM树组合构建渲染树Rander Tree,有了渲染树,浏览器就知道网页上有哪些节点以及每个节点的CSS属性。

Render Tree的构建其实就是DOM Tree和CSSOM Attach的过程,在webkit中,解析样式和创建呈现器的过程称为”附加”,每个DOM节点都有一个”attach”方法,Render Tree其实就相当于一个计算好样式,与HTML对应的Tree

4、Layout根据Render树进行布局渲染render layer,计算每个节点的几何结构(也就是计算出每个节点在屏幕上的位置)。

创建渲染树后,Layout根据根据渲染树中渲染对象的信息,计算好每一个渲染对象的位置和尺寸,将其放在浏览器窗口的正确位置,某些时候会在文档布局完成之后进行DOM修改,重新布局的过程就称为回流

5、Painting:将计算好的每个节点的布局信息绘制到屏幕上。

绘制阶段则会遍历呈现树,并调用呈现器的paint方法,将呈现器的内容显示在屏幕上,绘制的顺序其实就是元素进入堆栈样式上下文的顺序,例如,块呈现器的堆栈顺序如下:1.背景颜色,2.背景图片,3.边框,4.子代,5.轮廓

重绘(Repaint)和回流/重排(Reflow)

概念

重绘:样式发生改变,位置没有发生变动,页面不需要重新计算一次,重绘一次即可。

回流:位置发生了变化影响了其他元素的位置,需要重新计算位置即回流/重排,之后重绘。

重绘不一定回流,但回流必定重绘

重绘和回流的区别
  • 回流指当前窗口发生改变,发生滚动操作,或者元素的位置大小相关属性被更新时会触发布局过程,发生在render树,比如元素的几何尺寸变化,就需要重新验证并计算Render Tree
  • 重绘指当前视觉样式属性被更新时触发的绘制过程,发生在渲染层render layer
  • 回流的成本比重绘高
重绘和回流的应用
1、回流
  • 增加、删除、更新DOM节点
  • 通过display: none隐藏一个DOM节点(位置发生改变)
  • 元素尺寸发生变化(如边距)
  • 让一个DOM节点动画时
  • 添加样式,让整个样式发生改变
  • 改变窗口尺寸和滚动窗口
  • 计算offsetWidth、scrollTop、clientTop、getComputedStyle()等属性(获取这些属性的信息时需要返回新的布局信息,会强制队列刷新,触发回流)
2、重绘
  • 通过visibility: hidden隐藏一个节点需要重绘
减少回流重绘次数的方法
  • 避免一条一条的修改DOM样式,而是修改className或者style.classText
  • 对元素进行一个复杂的操作,可以先隐藏它,操作完成后在显示
  • 在需要经常获取那些引起浏览器回流的属性值时,要缓存到变量中
  • 不使用table布局,一个小的改动可能就会引起整个table重新布局
  • 在内存中多次操作节点,完成后在添加到文档中

白屏

页面没有加载完,就会出现白屏。

  • 对IE来说,把样式放在底部时,在某些场景下(如打开新窗口/刷新页面等)页面会出现白屏,而不是内容逐步展现。
  • 如果使用@import标签,即使将CSS写入外部样式表由link引入并放在头部,也可能出现白屏。
  • js文件放入页面顶部而未使用defer或async延迟或异步加载js文件,从而阻塞html与css的加载也会导致白屏。

FOUC

(Flash of unsettled content)无样式内容闪烁。 页面出现FOUC现象,具体表现为逐步加载无样式的内容,等CSS加载完成后页面突然展现样式。

把样式放在底部时,会先显示已加载的html内容,再逐步加载无样式内容,等css全部加载完成后页面突然展现样式。

CSS 和 JS 最佳放置顺序

  • 使用 link 标签将样式表放在顶部
  • JS放在底部
JS的阻塞问题
  • JS会阻塞DOM树的解析和渲染
  • 若JS位于页面顶部
    • JS脚本会阻塞后面内容的呈现
    • JS脚本会阻塞其后组件(如图片)的下载
    • JS加载时间过长,css需等待,则会出现一段时间白屏
CSS的阻塞问题
  • CSS会阻塞DOM树的渲染 (渲染树是依赖于CSSOM和DOM的,必须要等到CSSOM构建完成才能开始渲染)
  • CSS可能会阻塞DOM树的解析(若CSS阻塞JS语句,JS会阻塞DOM,则CSS可能阻塞DOM)
  • CSS会阻塞其后面JS语句的执行(JS可能会用到DOM节点和CSS样式)
  • 是一种优化机制避免回流

异步加载

<script src="script.js"></script>

放在顶部的这个js文件,会提前加载,如何使它在顶部仍然稍后加载?

async (异步脚本)

不让页面等待脚本下载和执行,从而异步加载页面其他内容(并行),异步脚本会在页面的load事件前执行。不保证顺序

<script async src="script.js"></script>
defer(延迟脚本)

js脚本会被延迟到整个页面都解析完成后再运行,会先于DOMContentLoaded事件执行。按顺序执行

<script defer src="script.js"></script>

作用:缩短了网页的加载时间,且他们的显示速度更快

页面加载

对于浏览器来说,页面加载主要有两个事件。DOMContentLoaded、onLoad

onLoad

等待页面所有资源加载完成才会触发。

DOMContentLoaded

等页面内容解析完就触发。

  • 若js在css前,则DOMContentLoaded不会等待css加载,也不会等待之后的图片、视频等其他资源加载。
  • 若js在css后,CSS阻塞其后面的js语句执行,js阻塞DOM解析,就导致DOMContentLoaded会等待CSS加载完执行。

参考引用:

https://juejin.im/post/6844903878949863432

https://github.com/okaychen/FE-Interview-Brochure/blob/master/html-and-css.md


评论
评论
  目录