<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>优化性能 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E4%BC%98%E5%8C%96%E6%80%A7%E8%83%BD/</link><description>Recent content in 优化性能 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 10 Nov 2024 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E4%BC%98%E5%8C%96%E6%80%A7%E8%83%BD/index.xml" rel="self" type="application/rss+xml"/><item><title>优化性能</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-026/</link><pubDate>Thu, 10 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/css/css-026/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;随着互联网发展至今，对于网站来说，性能显的越来越重要了，CSS作为页面渲染和内容展现的重要环节，影响着用户对整个网站的第一体验。所以，我们需要重视与CSS相关的性能优化。&lt;/p&gt;
&lt;p&gt;项目开发初期我们可能因为各种原因（很大一部分原因是因为项目工期，产品往往把项目上线时间卡的死死的，根本不听你说的什么性能优化），怎么写的舒服就怎么来，对于性能优化我们常常在项目完成时才去考虑，经常被推迟到项目的末期，甚至到暴露出严重的性能问题时才进行性能优化。&lt;/p&gt;
&lt;p&gt;为了更多地避免这一情况，首先要重视起性能优化相关的工作，将其贯穿到整个产品设计与开发中。其次，就是了解性能相关的内容，在项目开发过程中，自然而然地进行性能优化。&lt;/p&gt;
&lt;h2 id="css渲染规则"&gt;css渲染规则&lt;/h2&gt;
&lt;p&gt;想要优化CSS的性能，我们首先需要了解CSS的渲染规则，&lt;strong&gt;CSS选择器是从右向左进行匹配的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;来看个例子🌰：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.&lt;span style="color:#a6e22e"&gt;nav&lt;/span&gt; &lt;span style="color:#f92672"&gt;h3&lt;/span&gt; &lt;span style="color:#f92672"&gt;a&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;font-size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt;;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;渲染过程大概是：首先找到所有的&lt;code&gt;a&lt;/code&gt;，沿着&lt;code&gt;a&lt;/code&gt;的父元素查找&lt;code&gt;h3&lt;/code&gt;，然后再沿着&lt;code&gt;h3&lt;/code&gt;，查找&lt;code&gt;.nav&lt;/code&gt;。中途找到了符合匹配规则的节点就加入结果集。如果找到根元素&lt;code&gt;html&lt;/code&gt;都没有匹配，则不再遍历这条路径，从下一个&lt;code&gt;a&lt;/code&gt;开始重复这个查找匹配（只要页面上有多个最右节点为&lt;code&gt;a&lt;/code&gt;）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tips：为什么CSS选择器是从右向左匹配的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CSS中更多的选择器是不会匹配的，所以在考虑性能问题时，需要考虑的是如何在选择器不匹配时提升效率。从右向左匹配就是为了达成这一目的的，通过这一策略能够使得CSS选择器在不匹配的时候效率更高。这样想来，在匹配时多耗费一些性能也能够想的通了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="内联首屏关键csscritical-css"&gt;内联首屏关键CSS（Critical CSS）&lt;/h2&gt;
&lt;p&gt;性能优化中有一个重要的指标——&lt;strong&gt;首次有效绘制&lt;/strong&gt;（First Meaningful Paint，简称FMP）即指页面的首要内容（primary content）出现在屏幕上的时间。这一指标影响用户看到页面前所需等待的时间，而 &lt;strong&gt;内联首屏关键CSS（即Critical CSS，可以称之为首屏关键CSS）&lt;/strong&gt; 能减少这一时间。&lt;/p&gt;
&lt;p&gt;很多人都喜欢通过&lt;code&gt;link&lt;/code&gt;标签引用外部&lt;code&gt;CSS文件&lt;/code&gt;。但需要知道的是，&lt;strong&gt;将CSS直接内联到HTML文档中能使CSS更快速地下载&lt;/strong&gt;。而使用外部CSS文件时，需要在HTML文档下载完成后才知道所要引用的CSS文件，然后才下载它们。所以说，&lt;strong&gt;内联CSS能够使浏览器开始页面渲染的时间提前&lt;/strong&gt;，因为在HTML下载完成之后就能渲染了。&lt;/p&gt;
&lt;p&gt;但是我们不应该将所有的CSS都内联在HTML文档中，因为[初始拥塞窗口]存在限制&lt;code&gt;（TCP相关概念，通常是 14.6kB，压缩后大小）&lt;/code&gt;，如果内联CSS后的文件超出了这一限制，系统就需要在服务器和浏览器之间进行更多次的往返，这样并不能提前页面渲染时间。因此，我们应当&lt;strong&gt;只将渲染首屏内容所需的关键CSS内联到HTML中&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;⚠️还有一点需要注意的是内联CSS没有缓存，每次都会随HTML的加载而重新下载，但我们将内联首屏关键CSS控制在 &lt;code&gt;14.6kB&lt;/code&gt;以内，它对性能优化还是起到正向作用的。（凡事有利也有弊）&lt;/p&gt;
&lt;h2 id="异步加载非首屏css"&gt;异步加载非首屏CSS&lt;/h2&gt;
&lt;p&gt;我们需要知道两点内容：（具体可以看我之前的文章：&lt;a href="https://juejin.cn/post/7026536651899797541#heading-14"&gt;这些浏览器面试题，看看你能回答几个？&lt;/a&gt;）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CSS&lt;/code&gt;不会阻塞&lt;code&gt;DOM&lt;/code&gt;的解析，但会阻塞&lt;code&gt;DOM&lt;/code&gt;的渲染&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CSS&lt;/code&gt;会阻塞&lt;code&gt;JS&lt;/code&gt;执行，但不会阻塞&lt;code&gt;JS&lt;/code&gt;文件的下载&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于CSS会阻塞DOM的渲染，所以我们将首屏关键CSS内联后，剩余的非首屏CSS内容可以使用外部CSS，并且异步加载，防止非首屏CSS内容阻塞页面的渲染。&lt;/p&gt;
&lt;h3 id="css异步加载方式"&gt;CSS异步加载方式&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;第一种方法是动态创建&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 创建link标签
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;createElement&lt;/span&gt;( &lt;span style="color:#e6db74"&gt;&amp;#34;link&amp;#34;&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;href&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 插入到header的最后位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;insertBefore&lt;/span&gt;( &lt;span style="color:#a6e22e"&gt;myCSS&lt;/span&gt;, document.&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;childNodes&lt;/span&gt;[ document.&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;childNodes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ].&lt;span style="color:#a6e22e"&gt;nextSibling&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第二种方法是将link元素的&lt;code&gt;media&lt;/code&gt;属性设置为用户浏览器不匹配的媒体类型（或媒体查询）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对浏览器来说，如果样式表不适用于当前媒体类型，其优先级会被放低，会在不阻塞页面渲染的情况下再进行下载。在首屏文件加载完成之后，将&lt;code&gt;media&lt;/code&gt;的值设为&lt;code&gt;screen&lt;/code&gt;或&lt;code&gt;all&lt;/code&gt;，从而让浏览器开始解析CSS。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;media&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;noexist&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onload&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this.media=&amp;#39;all&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第三种方法是通过&lt;code&gt;rel&lt;/code&gt;属性将&lt;code&gt;link&lt;/code&gt;元素标记为&lt;code&gt;alternate&lt;/code&gt;可选样式表&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;alternate stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onload&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this.rel=&amp;#39;stylesheet&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第四种方法是使用&lt;code&gt;rel=preload&lt;/code&gt;来异步加载CSS&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;preload&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;mystyles.css&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;style&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onload&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;this.rel=&amp;#39;stylesheet&amp;#39;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，&lt;code&gt;as&lt;/code&gt;是必须的。忽略&lt;code&gt;as&lt;/code&gt;属性，或者错误的&lt;code&gt;as&lt;/code&gt;属性会使&lt;code&gt;preload&lt;/code&gt;等同于&lt;code&gt;XHR&lt;/code&gt;请求，浏览器不知道加载的是什么内容，因此此类资源加载优先级会非常低。&lt;code&gt;as&lt;/code&gt;的可选值可以参考上述标准文档。&lt;/p&gt;
&lt;p&gt;看起来，&lt;code&gt;rel=&amp;quot;preload&amp;quot;&lt;/code&gt;的用法和上面两种没什么区别，都是通过更改某些属性，使得浏览器异步加载CSS文件但不解析，直到加载完成并将修改还原，然后开始解析。&lt;/p&gt;
&lt;p&gt;但是它们之间其实有一个很重要的不同点，那就是&lt;strong&gt;使用preload，比使用不匹配的&lt;code&gt;media&lt;/code&gt;方法能够更早地开始加载CSS&lt;/strong&gt;。所以尽管这一标准的支持度还不完善，仍建议优先使用该方法。&lt;/p&gt;
&lt;h2 id="css文件压缩"&gt;CSS文件压缩&lt;/h2&gt;
&lt;p&gt;这应该是最容易想到的一个方法了，通过压缩CSS文件大小来提高页面加载速度。现在的构建工具，如webpack、gulp/grunt、rollup等也都支持CSS压缩功能。压缩后的文件能够明显减小，可以大大降低了浏览器的加载时间。&lt;/p&gt;
&lt;h2 id="css层级嵌套最好不要超过3层"&gt;CSS层级嵌套最好不要超过3层&lt;/h2&gt;
&lt;p&gt;一般情况下，元素的嵌套层级不能超过3级，过度的嵌套会导致代码变得臃肿，沉余，复杂。导致css文件体积变大，造成性能浪费，影响渲染的速度！而且过于依赖HTML文档结构。这样的css样式，维护起来，极度麻烦，如果以后要修改样式，可能要使用&lt;code&gt;!important&lt;/code&gt;覆盖。尽量&lt;strong&gt;保持简单，不要使用嵌套过多过于复杂的选择器。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="删除无用css代码"&gt;删除无用CSS代码&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一般情况下，会存在这两种无用的CSS代码：一种是不同元素或者其他情况下的重复代码，一种是整个页面内没有生效的CSS代码。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于前者，在编写的代码时候，我们应该尽可能地提取公共类，减少重复。对于后者，在不同开发者进行代码维护的过程中，总会产生不再使用的CSS的代码，当然一个人编写时也有可能出现这一问题。而这些无用的CSS代码不仅会增加浏览器的下载量，还会增加浏览器的解析时间，这对性能来说是很大的消耗。所以我们需要找到并去除这些无用代码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那么我们如何知道哪些CSS代码是无用代码呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;谷歌的Chrome浏览器就有这种开箱即用的功能。只需转到查看&amp;gt;开发人员&amp;gt;开发人员工具，并在最近的版本中打开Sources选项卡，然后打开命令菜单。然后，点击Coverage，在Coverage analysis窗口中高亮显示当前页面上未使用的代码。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/css/css-026/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="慎用通配符"&gt;慎用*通配符&lt;/h2&gt;
&lt;p&gt;我们有时候可能会写下面这种代码来消除一些标签的默认样式或统一浏览器对标签渲染的差异化：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;margin：0；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;padding：0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样虽然代码量少，但它的性能可不是最佳的，我们最好还是写对应的标签选择器：&lt;/p&gt;</description></item></channel></rss>