当前位置: 首页 > Web前端 > HTML

CSS和Web性能

时间:2023-04-02 20:19:01 HTML

CSS对于呈现页面至关重要-浏览器在找到、下载和解析所有CSS之前不会开始呈现-因此我们必须尽快将其加载到用户的设备上。关键路径上的任何延迟都会影响我们的“开始渲染”并给用户留下空白屏幕。有什么大不了的?从广义上讲,这就是CSS对性能至关重要的原因:在构建渲染树之前,浏览器无法渲染页面;渲染树是DOM和CSSOM的组合结果;DOM是HTML加上任何需要操纵JavaScript的阻塞;CSSOM是针对DOM应用的所有CSS规则;JavaScript很容易通过async和defer属性实现非阻塞;CSS不容易异步;所以要记住一个很好的经验法则,你的页面将在加载样式表后以最慢的速度显示。考虑到这一点,我们需要尽快构建DOM和CSSOM。在大多数情况下,构建DOM相对较快:您的第一个HTML响应是一个DOM。然而,由于CSS几乎总是HTML的子资源,因此构建CSSOM通常需要更长的时间。在这篇文章中,我想看看CSS如何证明是网络上的一个重大瓶颈(通过其自身和其他资源)以及我们如何缓解它,从而缩短关键路径并减少开始渲染的时间。使用CriticalCSS如果有办法,减少StartRender时间的最有效方法之一是使用CriticalCSS模式:确定StartRender所需的所有样式(通常是首屏所需的样式),以及将它们内联到中文档的将产生这个瀑布图:CausedbyinvalidpreloadscannerFirefoxloosesparallelization(注:同样的瀑布出现在IE/Edge中。)这个问题的直接解决方案是交换varscript=document.createElement('script');script.src="analytics.js";document.getElementsByTagName('head')[0].appendChild(script);是所有浏览器中有意且预期的迷人行为,但我从未见过一个理解它的开发人员。当您考虑到它可能带来的巨大性能影响时,这是非常令人惊讶的:如果当前有任何CSS加载,浏览器将不会执行console.log("我不会运行,直到slow-loading-stylesheet.css下载完成。");这是设计使然。这是故意的。当前正在下载任何CSS时,HTML中的任何同步可能询问页面样式的边缘情况:如果脚本在CSS到达并被解析之前询问页面的颜色,那么JavaScript给我们的答案可能不正确或陈旧。为了缓解这种情况,浏览器在构造CSSOM之前不会执行varscript=document.createElement('script');script.src="analytics.js";document.getElementsByTagName('head')[0].appendChild(script);根据这个序列,我们可以清楚地看到,在CSSOM构建之前,JavaScript文件甚至没有开始下载。我们完全失去了任何并行化:在异步代码部分之前有一个样式表会破坏我们并行化的机会。有趣的是,PreloadScanner期望提前引用analytics.js,但我们无意中隐藏了它:“analytics.js”是一个字符串,在<!-通常可能是净亏损。事实上,GoogleAnalytics甚至告诉我们该怎么做,他们是对的:复制此代码并将其粘贴为您要跟踪的每个网页的中的第一项。所以我的建议是:如果您的块不依赖于CSS,请将它们放在样式表之上。下面是当我们切换到这个模式时会发生什么:交换样式表和异步代码片段可以重新获得并行化。现在你可以看到我们已经完全恢复了并行化,页面加载速度几乎快了2倍。将任何非CSSOM查询JavaScript放在CSS之前;把任何CSSOM查询JavaScript放在CSS之后更进一步,除了异步加载片段之外,我们应该如何更普遍地加载CSS和JavaScript?为了解决这个问题,我提出了以下问题并从那里开始工作:如果:在CSSOM构造上的CSS块之后定义的同步JS;同步JS会阻止DOM构造-假设没有相互依赖-哪个更快/更受欢迎?脚本->样式;样式->脚本?答案是:如果文件不相互依赖,那么你应该将阻塞脚本放在阻塞样式之上——没有必要将JavaScript执行延迟到JavaScript实际上并不依赖的CSS。(预加载扫描器确保即使DOM构造在脚本上被阻止,CSS仍将被并行下载。)如果你的一些JavaScript依赖于CSS而另一些不依赖于CSS,那么加载同步JavaScript和CSS的绝对最佳顺序是将JavaScript分成两部分并将其加载到CSS的两侧:使用这种加载方式,我们可以最好的下载和执行命令。对于下面屏幕截图中的微小细节,我深表歉意,但希望您能看到代表JavaScript执行的粉红色小标记。entry(1)是计划在其他文件到达和/或执行时执行一些JavaScript的HTML;entry(2)在它到达的那一刻执行;entry(3)是CSS,所以没有执行JavaScript;在CSS完成之前,entry(4)不会真正执行。注意:您必须针对您自己的特定用例测试此模式:您可能会得到不同的结果,具体取决于您之前的CSSJavaScript文件与CSS本身在文件大小和执行成本方面是否存在巨大差异。测试,测试,测试。将放在中的最终策略是一个相对较新的策略,对感知性能和渐进式渲染有很大好处。它也非常友好。在HTTP/1.1中,我们通常将所有样式连接到一个主包中。我们称它为app.css:...

...

...
...
这引入了三个关键的低效率:任何给定的页面将只使用app.css中的一小部分样式:我们几乎肯定会下载比我们需要的更多的CSS。我们受到低效缓存策略的限制:例如,在仅用于一个页面的日期选择器上更改当前选定日期的背景颜色将需要我们缓存整个app.css。整个app.css阻塞渲染:如果当前页面只需要app.css的17%也没关系,我们还是要等另外83%开始渲染。使用HTTP/2,我们可以开始解决问题(1)和(2):...

...

...
...
现在我们正在解决冗余问题,因为我们能够加载更适合页面的CSS,而不是不加选择地下载所有内容这减少了关键路径上阻塞CSS的大小。我们还可以采用更有趣的缓存策略,只缓存需要它的文件,其余的保持不变。我们还没有解决的问题是它仍然阻止渲染——我们仍然只有最慢的样式表。这意味着如果出于某种原因site-footer.css需要很长时间才能下载,浏览器将无法开始呈现.site-header。然而,由于Chrome最近的变化(我相信版本69),以及Firefox和IE/Edge中已经存在的行为,仅阻止呈现后续内容,而不是整个页面。这意味着我们现在能够像这样构建我们的页面:...

...

......这样做的实际结果是我们现在能够逐步呈现我们的页面,其中页面可用有效地将页面交付样式添加到当前不支持此新行为的浏览器中的页面,我们不会遇到性能损失:我们退回到旧行为,我们只让最慢的CSS文件完成正在加载。将显示页面。这篇文章中有很多内容需要消化。它最终超出了我最初打算写成一篇文章的范围。试图总结加载CSS的最佳Web性能实践:LazyloadStartStartRenderAnyCSSNotNeeded:拆分关键CSS;或将您的CSS拆分为媒体查询。避免在您的HTML中使用@import:;尤其是在CSS中;之后定义的JavaScript将无法运行,因此如果您的JavaScript不依赖于您的CSS,请在您的CSS之前加载它;如果它取决于你的CSS,在你的CSS之后加载它。当DOM需要它时加载你的CSS,这将取消阻止“开始渲染”并允许渐进式渲染。我上面概述的所有内容都遵循规范或已知/预期的行为,但是,一如既往,自己测试所有内容。虽然这在理论上都是正确的,但在实践中事??情总是不同的。套用一句中国古话,知行合一。创建了一个程序员交流信息的微信群。大家进群交流IT技术,如果已经过期,可以加博主微信号15706211347拉你进群