关键渲染路径

关键渲染路径是浏览器将 HTML,CSS 和 JavaScript 转换为屏幕上的像素所经历的步骤序列。优化关键渲染路径可提高渲染性能。关键渲染路径包含了 文档对象模型(DOM),CSS 对象模型 (CSSOM),渲染树和布局。

在解析 HTML 时会创建文档对象模型。HTML 可以请求 JavaScript,而 JavaScript 反过来,又可以更改 DOM。HTML 包含或请求样式,依次来构建 CSS 对象模型。浏览器引擎将两者结合起来以创建渲染树。布局确定页面上所有内容的大小和位置。确定布局后,将像素绘制到屏幕上。

优化关键渲染路径可以缩短首次渲染的时间。了解和优化关键渲染路径对于确保重排和重绘可以每秒 60 帧的速度进行,以确保高效的用户交互并避免卡顿是很重要的。

理解 CRP

Web 性能包含了服务器请求和响应、加载、执行脚本、渲染、布局和绘制每个像素到屏幕上。

网页请求从 HTML 文件请求开始。服务器返回 HTML——响应头和数据。然后浏览器开始解析 HTML,转换收到的数据为 DOM 树。浏览器每次发现外部资源就初始化请求,无论是样式、脚本或者嵌入的图片引用。有时请求会阻塞,这意味着解析剩下的 HTML 会被终止直到重要的资源被处理。浏览器接着解析 HTML,发请求和构造 DOM 直到文件结尾,这时开始构造 CSS 对象模型。等到 DOM 和 CSSOM 完成之后,浏览器构造渲染树,计算所有可见内容的样式。一旦渲染树完成布局开始,定义所有渲染树元素的位置和大小。完成之后,页面被渲染完成,或者说是绘制到屏幕上。

文档对象模型

DOM 构建是增量的。HTML 响应变成令牌(token),令牌变成节点,而节点又变成 DOM 树。单个 DOM 节点以 startTag 令牌开始,以 endTag 令牌结束。节点包含有关 HTML 元素的所有相关信息。该信息是使用令牌描述的。节点根据令牌层次结构连接到 DOM 树中。如果另一组 startTag 和 endTag 令牌位于一组 startTag 和 endTag 之间,则你在节点内有一个节点,这就是我们定义 DOM 树层次结构的方式。

节点数量越多,关键渲染路径中的后续事件将花费的时间就越长。测一下吧!几个额外的节点不会有什么区别,但“DIV 癖”(divitis)可能会导致问题。

CSS 对象模型

DOM 包含页面所有的内容。CSSOM 包含了页面所有的样式,也就是如何展示 DOM 的信息。CSSOM 跟 DOM 很像,但是不同。DOM 构造是增量的,CSSOM 却不是。CSS 是渲染阻塞的:浏览器会阻塞页面渲染直到它接收和执行了所有的 CSS。CSS 是渲染阻塞是因为规则可以被覆盖,所以内容不能被渲染直到 CSSOM 的完成。

CSS 有其自身的规则集合用来定义标识。注意 CSS 中的 C 代表的是“层叠”。CSS 规则是级联的。随着解析器转换标识为节点,节点的后代继承了样式。像处理 HTML 那样的增量处理功能没有被应用到 CSS 上,因为后续规则可能被之前的所覆盖。CSS 对象模型随着 CSS 的解析而被构建,但是直到完成都不能被用来构建渲染树,因为样式将会被之后的解析所覆盖而不应该被渲染到屏幕上。

从选择器性能的角度,更少的特定选择器是比更多的要快。例如,.foo {} 是比 .bar .foo {} 更快的因为当浏览器发现 .foo ,接下来必须沿着 DOM 向上走来检查 .foo 是不是有一个祖先 .bar。越是具体的标签浏览器就需要更多的工作,但这样的弊端未必值得优化。

如果你测量过解析 CSS 的时间,你将会被浏览器实在地快所震惊。更具体的规则更昂贵因为它必须遍历更多的 DOM 树节点,但这所带来的额外的消耗通常很小。先测量一下。然后按需优化。特定化或许不是你的低垂的果实。在 CSS 中选择器的性能优化,提升仅仅是毫秒级的。有其他一些方式来优化 CSS,例如压缩和使用媒体查询来异步处理 CSS 为非阻塞的请求。

渲染树

渲染树包括了内容和样式:DOM 和 CSSOM 树结合为渲染树。为了构造渲染树,浏览器检查每个节点,从 DOM 树的根节点开始,并且决定哪些 CSS 规则被添加。

渲染树只包含了可见内容。头部(通常)不包含任何可见信息,因此不会被包含在渲染树中。如果有元素上有 display: none;,它本身和其后代都不会出现在渲染树中。

布局

一旦渲染树被构建,布局变成了可能。布局取决于屏幕的尺寸。布局这个步骤决定了在哪里和如何在页面上放置元素,决定了每个元素的宽和高,以及他们之间的相关性。

什么是一个元素的宽?块级元素,根据定义,默认有父级宽度的 100%。一个宽度 50% 的元素,将占据父级宽度的一半。除非另外定义,body 有 100% 的宽,意味着它占据视窗的 100%。设备的宽度影响布局。

视窗的元标签定义了布局视窗的宽度,从而影响布局。没有的话,浏览器使用视窗的默认宽度,默认全屏浏览器通常是 960px。在默认情况下像你的手机浏览器的全屏浏览器,通过设置 <meta name="viewport" content="width=device-width">,宽度将会是设备的宽度而不是默认的视窗宽度。设备宽度当用户在横向和纵向模式旋转他们的手机时将会改变。布局发生在每次设备旋转或浏览器缩放时。

布局性能受 DOM 影响——节点数越多,布局就需要更长的时间。布局将会变成瓶颈,如果期间需要滚动或者其他动画将会导致迟滞。20ms 的延迟在加载或者方向改变时或许还可以接受,但在动画或滚动时就会迟滞。任何渲染树改变的时候,像添加节点、改变内容或者在一个节点更新盒模型样式的时候布局就会发生。

为了减小布局事件的频率和时长,批量更新或者避免改动盒模型属性。

绘制

最后一步是将像素绘制在屏幕上。一旦渲染树创建并且布局完成,像素就可以被绘制在屏幕上。加载时,整个屏幕被绘制出来。之后,只有受影响的屏幕区域会被重绘,浏览器被优化为只重绘需要绘制的最小区域。绘制时间取决于何种类型的更新被附加在渲染树上。绘制是一个非常快的过程,所以聚焦在提升性能时这大概不是最有效的部分,重点要记住的是当测量一个动画帧需要的时间需要考虑到布局和重绘时间。添加到节点的样式会增加渲染时间,但是移除样式增加的 0.001ms 或许不能让你的优化物有所值。记住先测量。然后你可决定它的优化优先级。

优化 CRP

提升页面加载速度需要通过被加载资源的优先级、控制它们加载的顺序和减小这些资源的体积。性能提示包含 1)通过异步、延迟加载或者消除非关键资源来减少关键资源的请求数量,2)优化必须的请求数量和每个请求的文件体积,3)通过区分关键资源的优先级来优化被加载关键资源的顺序,来缩短关键路径长度。