1. 首页

CSS 是如何工作的:关键渲染路径中的 CSS 解析和渲染

CSS 是一种神奇又古怪的力量,他控制着网页上我们看到的一切。本质上他应该很简单,但是真要写出可拓展、高性能的 CSS 又没那么容易。

不管你觉得 CSS 是“必经之痛”还是被大家误解了,CSS 依旧是每个 web 开发者必须掌握的能力。对CSS的理解深浅将会决定你的网站是光鲜亮丽还是平淡无奇。

这篇文章是深入了解 CSS 系列文章的第一篇。通过掀开CSS神秘的面纱,我们能够更深入的理解这门语言,让我们可以写出更快、更简洁、更漂亮的 CSS,来适应我们的应用程序规模和复杂度的增长。

在这篇文章中,我们将要研究页面初次加载后,CSS 是如何被渲染到屏幕上的。

我们之所以关心 CSS 的渲染过程,归结为下面两点:

加载时间

如果你的网站加载太慢,就算它的内容很有价值,用户也很有可能会在它加载完成前就关闭网页。一些研究表明,如果页面加载时间超过 3s,超过 50% 的用户会离开。

基于用户对于加载时间的期望,作为 web 开发者,我们应当减少用户的等待时间。不幸的是,CSS 通常是导致加载时间增加的罪魁祸首,所以如果你对 CSS 是如何被渲染到像素的有细致的了解,将会帮助你优化这关键的几秒,提升用户的留存。

然而,什么是关键渲染路径?

想让网页加载更快,首先需要区分关键资源与非关键资源。也许你已经应用了某些策略,让一些图片使用懒加载,根据路由拆分 JavaScript 按需加载(感谢 webpack)。这些在页面初次渲染完成后才加载的资源,就是我们所说的非关键资源,这些资源不会影响页面初次渲染的时间。那些会影响初次渲染时间的资源,才是至关重要的。

关键渲染路径是从浏览器收到 HTML 第一个字节起到开始渲染像素所要经历的最少步骤。本质上,它是浏览器对关键资源进行处理、渲染、展示给用户的过程。这个过程大致如下:

  • 根据收到的 HTML 创建 DOM(文档对象模型)
  • 如果遇到 CSS(内联或者外链)则开始创建 CSSOM(CSS 对象模型—后面会详细说明)
  • 如果遇到 JavaScript(非异步)则停止 DOM 构建,等待 CSSOM 构建完毕后再解析和执行。这么做的原因是 JavaScript 可能会修改和访问 DOM 和 CSSOM。

研究的第二个步骤:CSS 是如何影响关键渲染路径的。对于 JavaScript,我们使用了诸如 tree-shake、路由拆分、懒加载各种手段进行优化,对于 CSS 的优化则经常被我们忽视,实际上,未优化的 CSS 能轻而易举地让你的加载时间增加。

HTML 和关键渲染路径

既然我们的重点是 CSS,我们不会花太多篇幅在 DOM 构建上。然而,CSS 是一个样式标记语言,我们要知道它是如何和 DOM 工作的。

DOM 是包含页面所有 HTML 节点的类树形结构。每一个节点包含了 HTML 元素的数据(比如属性、id、class)。如果 HTML 元素有子节点,它会指向这些子节点。比如,下图中的 HTML 将会构建出右边的 DOM 结构。会发现 HTML 的缩进和 DOM 结构的十分相似。

分析关键渲染路径性能 , Web , Google Developers

从关键渲染路径这个角度来看,我们认为 HTML 是一个阻碍渲染的关键资源。在未解析完 HTML 之前,任何内容都无法被渲染。

创建 CSS对象模型

当浏览器解析到一个 CSS 样式表(不管是内联还是外链)时,需要解析文本,使之可以用于样式排布和绘制。这种数据结构就是 CSSOM。

CSSOM 长什么样子?下图中的 CSS 将会构建出右边的 CSSOM

阻塞渲染的CSS , Web ,Google,优化页面加载速度环节众多,今天要说的是关键渲染路径(critical .... 动态插入的外链CSS 不会阻塞DOM 的解析或渲染; 动态插入的内联CSS 会 ...

本质上,我们通过解析所有的 CSS 选择器并将它插入到树中对应的位置。如果是一个单独的选择器,将会被添加到树的根节点下。嵌套的选择器将会被添加到嵌套的节点下。CSS 解析器将会从右往左遍历选择器来保证其正确性。

解析 CSS 到 CSSOM 和通过 HTML 构建 DOM 一样,是一个阻碍渲染的过程。如果不等待 CSSOM 的构建而开始渲染,将会导致用户短暂看到没有样式的内容,然后被应用上 CSS 的样式,这不是一个好的用户体验。

渲染树

浏览器用构建好的 CSSOM 和 DOM 来创建一个渲染树。简单来说,渲染树包含了需要渲染像素到屏幕上的所有信息。浏览器将 DOM 和 CSSOM 整合到一起,同时移除对渲染输出没有影响的内容。

浏览器首先会移除那些不可见的元素。包括 <head> <script> <meta> 这些标签,以及有 hidden 属性的 HTML 元素。这些元素虽然在其他地方有用到,但是并不会渲染到页面上,基于这个原理,浏览器渲染时能够确保渲染树上的所有节点都是可见的。

接下来,遍历 CSSOM,找到与渲染树上节点相匹配的 CSS 选择器。任何匹配到的 CSS 规则将会被应用到该节点上。

然而有一个 CSS 规则例外:display: none; 它将会匹配到的节点从渲染树上完全移除,这样保证了只保留可见元素。其他隐藏元素的方法,如 opacity: 0; 将不会从渲染树中移除,只是进行渲染却不显示。

JavaScriptc中文网 – 前端进阶资源分享 www.javascriptc.com,公众号:IT平头哥联盟

当我们拥有了这个渲染树,一切准备就绪!在我们整合完 CSSOM 和 DOM 到渲染树后,渲染树就只包含了那些需要被渲染的信息,浏览器就可以使用它进行安全精确的渲染,这些信息没有冗余,也没有缺失。

冲刺阶段:布局和绘制

配备了完整的渲染树,浏览器已经可以开始渲染像素到屏幕上了。关键渲染路径的最后阶段包括两个步骤:布局和绘制。

布局是浏览器通过 CSS 规则计算 marginpaddingwidthposition,从而得到元素的位置和所需的空间的过程。在计算布局的时候,由于元素的位置、宽度、高度是由其父元素计算而来,浏览器从渲染树的顶端向下遍历。

如果你对 CSS 盒子模型很熟悉的话,本质上就是浏览器在页面上绘制了一系列 CSS 盒子(如果你想要了解盒子模型,可以阅读这篇)。

然而,要注意这个时候页面上还没有显示任何内容。想象成仅仅是在视窗上绘制了轮廓线,等待开始填充。

布局之后就是绘制阶段,然后我们就可以看到内容被渲染到页面上!这就是首像素渲染时间。浏览器遍历非布局的 CSS 规则并且填充 CSS 盒子。如果你用了多个图层,浏览器会保证其绘制到正确的图层。

请记住,一些 CSS 属性对页面负载有很大影响(比如,radial-gradient 比纯色渲染就更为复杂)。如果你在绘制过程中发现一些闪跳,减少这种渲染代价高的 CSS 规则可以显著提高网站的性能。

为什么要关心关键渲染路径中的 CSS?

你可以花尽可能多的时间来优化网站的 FPS(每秒的渲染帧数),使它看起来更好,或者通过 A-B test 来获得更高的转化率。但是如果你的用户在页面加载完成前离开了,这些都将变成无用功。

如果你在尝试提高页面加载速度,知道浏览器需要哪些步骤才能渲染出第一像素是至关重要的。既然浏览器在解析全部 CSS 之前会阻碍渲染,那么可以在 HTML 文档中去掉那些不会在首次页面渲染中使用到的 CSS 文件。这么做可以大幅度降低浏览器构建 CSSOM 和渲染树的时间。

那些在初次加载中并非必要的 CSS 可以被认为是非关键资源,可以通过懒加载,在用户看到初次渲染页面之后再加载(如果你的页面是一个单页应用,这将会特别重要,传送那些还看不到页面的 CSS 对性能有很大影响)。

理解 CSSOM 是如何构建的另一个好处,是可以对选择器性能有更深入的了解。因为嵌套的选择器必须检查 CSSOM 上的父节点,所以尽量避免使用嵌套的选择器,可以提升 CSSOM 的性能。然而,我想说的是,在大多数的应用程序中,它并不会成为性能的瓶颈,相对于重写 CSS 选择器,还有其他更值得优化的地方。

和其他 web 性能相关的问题一样,在修改 CSS 之前,你最好可以分析下加载时间。如果你在使用 Chrome,打开工具栏切换到 Perfomarnce 标签下。你可以通过 Recalculate Styles、 Layout 和 Paint 这些事件,看到 CSSOM 构建、排版、绘制所需的时间。然后你可以根据瓶颈来针对性的开始优化。

JavaScriptc中文网 – 前端进阶资源分享 www.javascriptc.com

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文来源于网络,其版权属原作者所有,如有侵权,请与小编联系,谢谢!

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:CSS 是如何工作的:关键渲染路径中的 CSS 解析和渲染

链接:https://www.javascriptc.com/384.html

原文链接:https://github.com/yued-fe/y-translation/blob/master/todo/how-css-works-parsing-painting-css-in-the-critical-rendering-path.md

« 装饰器(Decorator)到底是个什么鬼?
那些年面试踩过的坑,都在这里了~»
Flutter 中文教程资源

相关推荐

QR code