关键渲染路径
关键渲染路径是浏览器将 HTML、CSS 和 JavaScript 转换为屏幕上的像素所经历的一系列步骤。优化关键渲染路径可以提高渲染性能。关键渲染路径包括文档对象模型 (DOM)、CSS 对象模型 (CSSOM)、渲染树和布局。
在解析 HTML 时创建文档对象模型。HTML 可能会请求 JavaScript,而 JavaScript 又可能会更改 DOM。HTML 包含或发出对样式的请求,这些样式又会构建 CSS 对象模型。浏览器引擎将两者结合起来创建渲染树。布局确定页面上所有内容的大小和位置。确定布局后,像素就会绘制到屏幕上。
优化关键渲染路径可以缩短首次渲染时间。了解和优化关键渲染路径对于确保重排和重绘能够以每秒 60 帧的速度发生、确保用户交互的性能以及避免卡顿非常重要。
了解 CRP
Web 性能包括服务器请求和响应、加载、脚本、渲染、布局以及将像素绘制到屏幕上。
对网页或应用程序的请求始于 HTTP 请求。服务器发送包含 HTML 的响应。然后浏览器开始解析 HTML,将接收到的字节转换为 DOM 树。浏览器每次找到指向外部资源(无论是样式表、脚本还是嵌入的图像引用)的链接时,都会启动请求。一些请求是阻塞的,这意味着在处理导入的资源之前,其余 HTML 的解析会暂停。浏览器继续解析 HTML,发出请求并构建 DOM,直到到达末尾,此时它会构建 CSS 对象模型。在 DOM 和 CSSOM 完成后,浏览器构建渲染树,计算所有可见内容的样式。渲染树构建完成后,就会发生布局,定义所有渲染树元素的位置和大小。完成后,页面就会渲染或“绘制”到屏幕上。
文档对象模型
DOM 构建是增量的。HTML 响应变为标记,标记变为节点,节点变为 DOM 树。单个 DOM 节点以 startTag 标记开始,以 endTag 标记结束。节点包含有关 HTML 元素的所有相关信息。信息使用标记进行描述。节点根据标记层次结构连接到 DOM 树中。如果另一组 startTag 和 endTag 标记出现在一组 startTag 和 endTag 标记之间,则表示一个节点在另一个节点内部,这就是我们定义 DOM 树层次结构的方式。
节点数量越多,关键渲染路径中的后续事件所需的时间就越长。进行测量!几个额外的节点不会产生很大影响,但请记住,添加许多额外的节点会影响性能。
CSS 对象模型
DOM 包含页面上的所有内容。CSSOM 包含有关如何设置 DOM 样式的所有信息。CSSOM 与 DOM 类似,但有所不同。虽然 DOM 构建是增量的,但 CSSOM 不是。CSS 是渲染阻塞的:浏览器会阻止页面渲染,直到它接收并处理所有 CSS。CSS 是渲染阻塞的,因为规则可以被覆盖,因此在 CSSOM 完成之前无法渲染内容。
CSS 有自己的一套规则来识别有效标记。请记住,CSS 中的 C 代表“层叠”。CSS 规则会层叠。当解析器将标记转换为节点时,子节点将继承父节点的一些样式。增量处理功能不适用于 CSS,就像 HTML 那样,因为后续规则可能会覆盖先前的规则。CSS 对象模型在解析 CSS 时构建,但直到完全解析后才能用于构建渲染树,因为要被后续解析覆盖的样式不应渲染到屏幕上。
在选择器性能方面,不太具体的选择器比更具体的选择器更快。例如,.foo {}
比 .bar .foo {}
快,因为当浏览器找到 .foo
时,在第二种情况下,它必须向上遍历 DOM 以检查 .foo
是否具有祖先 .bar
。更具体的标签需要浏览器做更多工作,但这项开销可能不值得优化。
如果测量解析 CSS 所需的时间,您会惊叹于浏览器的速度。更具体的规则开销更大,因为它必须遍历 DOM 树中的更多节点——但这种额外开销通常很小。先测量。根据需要优化。特异性可能不是您最容易解决的问题。在 CSS 方面,选择器性能优化改进只会以微秒为单位。还有其他优化 CSS 的方法,例如缩小和通过使用媒体查询将延迟 CSS 分离到非阻塞请求中。
渲染树
渲染树同时捕获内容和样式:DOM 和 CSSOM 树合并到渲染树中。为了构建渲染树,浏览器会检查每个节点(从 DOM 树的根节点开始),并确定哪些 CSS 规则附加到该节点。
渲染树仅捕获可见内容。head 部分(通常)不包含任何可见信息,因此不包含在渲染树中。如果元素上设置了 display: none;
,则它及其任何后代都不会出现在渲染树中。
布局
构建渲染树后,布局就成为可能。布局取决于屏幕大小。布局步骤确定元素在页面上的位置和显示方式,确定每个元素的宽度和高度,以及它们彼此之间的关系。
元素的宽度是多少?根据定义,块级元素的默认宽度为其父级宽度的 100%。宽度为 50% 的元素将是其父级宽度的一半。除非另有定义,否则 body 的宽度为 100%,这意味着它将是视口宽度的 100%。设备的宽度会影响布局。
视口元标记定义了布局视口的宽度,从而影响布局。如果没有它,浏览器将使用默认的视口宽度,在默认全屏浏览器中通常为 960px。在默认全屏浏览器(如手机浏览器)中,通过设置 <meta name="viewport" content="width=device-width">
,宽度将是设备的宽度而不是默认视口宽度。当用户在横向和纵向模式之间旋转手机时,device-width 会发生变化。每次旋转设备或调整浏览器大小都会发生布局。
DOM 会影响布局性能——节点数量越多,布局所需的时间就越长。如果在滚动或其他动画期间需要布局,它可能会成为瓶颈,导致卡顿。虽然加载或方向更改时 20 毫秒的延迟可能没问题,但它会导致动画或滚动时的卡顿。每当渲染树被修改(例如,添加节点、更改内容或更新节点上的盒模型样式)时,都会发生布局。
为了减少布局事件的频率和持续时间,请批量更新并避免对盒模型属性进行动画处理。
绘制
最后一步是将像素绘制到屏幕上。创建渲染树并发生布局后,就可以将像素绘制到屏幕上。加载时,整个屏幕都会被绘制。之后,只会重新绘制屏幕上受影响的区域,因为浏览器经过优化,可以重新绘制所需的最小区域。绘制时间取决于应用于渲染树的更新类型。虽然绘制过程非常快,因此可能不是提高性能时最值得关注的地方,但请务必记住,在测量动画帧可能需要多长时间时,要考虑布局和重新绘制时间。应用于每个节点的样式会增加绘制时间,但删除使绘制时间增加 0.001 毫秒的样式可能不会为您带来最大的优化收益。请务必先进行测量。然后,您可以确定它是否应成为优化的优先事项。
优化 CRP
通过优先考虑加载哪些资源、控制加载顺序以及减小这些资源的文件大小来提高页面加载速度。性能技巧包括 1) 通过延迟非关键资源的下载、将其标记为异步或完全消除它们来最大程度地减少关键资源的数量,2) 优化每个请求所需请求的数量以及每个请求的文件大小,以及 3) 通过优先下载关键资产来优化关键资源的加载顺序,从而缩短关键路径长度。