>  기사  >  웹 프론트엔드  >  CSS 성능을 최적화하는 방법은 무엇입니까? 최적화 팁 공유

CSS 성능을 최적화하는 방법은 무엇입니까? 최적화 팁 공유

青灯夜游
青灯夜游앞으로
2022-03-23 10:49:202302검색

CSS 성능을 최적화하는 방법은 무엇입니까? 다음 글에서는 CSS 성능 최적화 팁을 소개하겠습니다. 도움이 되길 바랍니다.

CSS 성능을 최적화하는 방법은 무엇입니까? 최적화 팁 공유

인터넷이 발전하면서 웹 사이트의 성능이 점점 더 중요해졌습니다. 페이지 렌더링 및 콘텐츠 표현의 중요한 부분인 CSS는 전체 웹 사이트에 대한 사용자의 첫 경험에 영향을 미칩니다. 그러므로 우리는 CSS와 관련된 성능 최적화에 주목할 필요가 있습니다. [추천 학습: css 동영상 튜토리얼]

프로젝트 개발 초기에는 여러 가지 이유가 있을 수 있습니다. (이유의 상당 부분은 프로젝트 기간 때문입니다. 제품이 프로젝트를 완료하는 데 시간이 걸리는 경우가 종종 있습니다. 온라인에 가서 당신의 말을 전혀 듣지 않습니다. 성능 최적화를 위해 프로젝트가 완료된 후에만 고려하는 경우가 많습니다. , 또는 심각한 성능 문제가 노출된 경우에도 마찬가지입니다.

이러한 상황을 피하기 위해서는 먼저 성능 최적화와 관련된 작업에 주의를 기울이고 이를 전체 제품 설계 및 개발에 통합해야 합니다. 둘째, 프로젝트 개발 과정에서 성능 관련 내용을 이해하고 자연스럽게 성능 최적화를 수행하는 것이다.

css 렌더링 규칙

CSS 성능을 최적화하려면 먼저 CSS의 렌더링 규칙을 이해해야 합니다. CSS 선택자는 오른쪽에서 왼쪽으로 일치합니다.

예를 살펴보겠습니다.

.nav h3 a{font-size: 14px;}复制代码

렌더링 프로세스는 아마도 다음과 같습니다. 먼저 모든 a를 찾고 a의 상위 요소를 따라 h3를 검색한 다음 h3를 따릅니다. >, .nav를 찾으세요. 일치 규칙을 충족하는 노드가 중간에 발견되면 결과 집합에 추가됩니다. 루트 요소 html와 일치하는 항목이 없으면 경로는 더 이상 순회되지 않으며 다음 a부터 시작하여 검색이 반복됩니다(여러 개가 있는 한). a에 대한 페이지의 가장 오른쪽 노드). a,沿着a的父元素查找h3,然后再沿着h3,查找.nav。中途找到了符合匹配规则的节点就加入结果集。如果找到根元素html都没有匹配,则不再遍历这条路径,从下一个a开始重复这个查找匹配(只要页面上有多个最右节点为a)。

Tips:为什么CSS选择器是从右向左匹配的?

CSS中更多的选择器是不会匹配的,所以在考虑性能问题时,需要考虑的是如何在选择器不匹配时提升效率。从右向左匹配就是为了达成这一目的的,通过这一策略能够使得CSS选择器在不匹配的时候效率更高。这样想来,在匹配时多耗费一些性能也能够想的通了。

内联首屏关键CSS(Critical CSS)

性能优化中有一个重要的指标——首次有效绘制(First Meaningful Paint,简称FMP)即指页面的首要内容(primary content)出现在屏幕上的时间。这一指标影响用户看到页面前所需等待的时间,而 内联首屏关键CSS(即Critical CSS,可以称之为首屏关键CSS) 能减少这一时间。

很多人都喜欢通过link标签引用外部CSS文件。但需要知道的是,将CSS直接内联到HTML文档中能使CSS更快速地下载。而使用外部CSS文件时,需要在HTML文档下载完成后才知道所要引用的CSS文件,然后才下载它们。所以说,内联CSS能够使浏览器开始页面渲染的时间提前,因为在HTML下载完成之后就能渲染了。

但是我们不应该将所有的CSS都内联在HTML文档中,因为[初始拥塞窗口]存在限制(TCP相关概念,通常是 14.6kB,压缩后大小),如果内联CSS后的文件超出了这一限制,系统就需要在服务器和浏览器之间进行更多次的往返,这样并不能提前页面渲染时间。因此,我们应当只将渲染首屏内容所需的关键CSS内联到HTML中

⚠️还有一点需要注意的是内联CSS没有缓存,每次都会随HTML的加载而重新下载,但我们将内联首屏关键CSS控制在 14.6kB以内,它对性能优化还是起到正向作用的。(凡事有利也有弊)

异步加载非首屏CSS

我们需要知道两点内容:(具体可以看我之前的文章:这些浏览器面试题,看看你能回答几个?

  • CSS不会阻塞DOM的解析,但会阻塞DOM的渲染
  • CSS会阻塞JS执行,但不会阻塞JS
팁: CSS 선택자가 오른쪽에서 왼쪽으로 일치하는 이유는 무엇인가요?

CSS에서 선택자가 더 이상 일치하지 않으므로 성능 문제를 고려할 때 고려해야 할 것은 선택자가 일치하지 않을 때 효율성을 높이는 방법입니다. 오른쪽에서 왼쪽으로 일치하는 것은 이 목적을 달성하기 위한 것입니다. 이 전략은 일치하지 않을 때 CSS 선택기를 더 효율적으로 만들 수 있습니다. 이렇게 생각하면 매칭 시 더 많은 성능을 소모하는 것이 합리적입니다.

인라인 첫 화면 중요 CSS(Critical CSS) 성능 최적화에 중요한 지표가 있습니다 -

첫 번째 효과적인 페인팅

(첫 번째 의미 있는 페인트, FMP)는 페이지의 주요 콘텐츠가 화면에 나타나는 시간을 나타냅니다. 이 표시기는 사용자가 페이지를 보기 전에 기다려야 하는 시간에 영향을 미치며,

Inline important CSS(Critical CSS, 첫 번째 화면 중요 CSS라고도 함)는 이 시간을 줄일 수 있습니다.

많은 사람들이 link 태그를 통해 외부 CSS 파일을 참조하는 것을 좋아합니다. 하지만 알아야 할 것은 🎜CSS를 HTML 문서에 직접 인라인하면 CSS 다운로드 속도가 더 빨라질 수 있다는 것입니다🎜. 외부 CSS 파일을 사용하는 경우 HTML 문서 다운로드 후 참조할 CSS 파일을 알고 다운로드해야 합니다. 따라서 🎜인라인 CSS를 사용하면 HTML 다운로드가 완료된 후에 렌더링할 수 있으므로 브라우저가 페이지 렌더링을 더 일찍 시작하도록🎜 할 수 있습니다. 🎜🎜하지만 HTML 문서에 모든 CSS를 인라인하면 안 되는데, 인라인인 경우 [초기 혼잡 창] (TCP 관련 개념, 보통 14.6kB, 압축 크기)에 제한이 있기 때문입니다. CSS가 이 제한을 초과하면 시스템은 서버와 브라우저 간에 더 많은 왕복을 수행해야 하므로 페이지 렌더링 시간이 빨라지지 않습니다. 따라서 🎜 스크롤 없이 볼 수 있는 콘텐츠를 HTML로 렌더링하는 데 필요한 중요한 CSS만 🎜 HTML에 인라인해야 합니다. 🎜🎜⚠️또 한 가지 주의할 점은 인라인 CSS는 캐시되지 않으며 HTML이 로드될 때마다 다시 다운로드된다는 점입니다. 그러나 인라인 첫 화면의 주요 CSS는 14.6kB 내에서 제어됩니다. 이는 여전히 성능 최적화에 긍정적인 역할을 합니다. (모든 것에는 장단점이 있습니다) 🎜

첫 화면이 아닌 CSS의 비동기 로딩🎜🎜두 가지를 알아야 합니다: (자세한 내용은 이전 기사를 참조하세요. 이 브라우저 인터뷰 질문은, 몇 개나 대답할 수 있나요? 🎜) 🎜
  • CSSDOM의 구문 분석을 차단하지 않습니다. DOM 렌더링 차단 🎜
  • CSSJS 실행을 차단하지만 JS files🎜🎜🎜CSS는 DOM 렌더링을 차단하므로 첫 번째 화면에 핵심 CSS를 인라인한 후 첫 화면 외부의 나머지 CSS 콘텐츠는 외부 CSS를 사용하고 CSS 콘텐츠가 렌더링되는 것을 방지하기 위해 비동기적으로 로드할 수 있습니다. 첫 번째 화면 외부에서 페이지 렌더링을 차단합니다. 🎜🎜🎜🎜CSS 비동기 로딩 방식🎜🎜🎜🎜🎜첫 번째 방식은 동적으로 생성하는 것🎜🎜<pre class="brush:js;toolbar:false;">// 创建link标签 const myCSS = document.createElement( &quot;link&quot; ); myCSS.rel = &quot;stylesheet&quot;; myCSS.href = &quot;mystyles.css&quot;; // 插入到header的最后位置 document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );</pre><p><strong>第二种方法是将link元素的<code>media属性设置为用户浏览器不匹配的媒体类型(或媒体查询)

    对浏览器来说,如果样式表不适用于当前媒体类型,其优先级会被放低,会在不阻塞页面渲染的情况下再进行下载。在首屏文件加载完成之后,将media的值设为screenall,从而让浏览器开始解析CSS。

    <link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media=&#39;all&#39;">

    第三种方法是通过rel属性将link元素标记为alternate可选样式表

    <link rel="alternate stylesheet" href="mystyles.css" onload="this.rel=&#39;stylesheet&#39;">

    第四种方法是使用rel=preload来异步加载CSS

    <link rel="preload" href="mystyles.css" as="style" onload="this.rel=&#39;stylesheet&#39;">

    注意,as是必须的。忽略as属性,或者错误的as属性会使preload等同于XHR请求,浏览器不知道加载的是什么内容,因此此类资源加载优先级会非常低。as的可选值可以参考上述标准文档。

    看起来,rel="preload"的用法和上面两种没什么区别,都是通过更改某些属性,使得浏览器异步加载CSS文件但不解析,直到加载完成并将修改还原,然后开始解析。

    但是它们之间其实有一个很重要的不同点,那就是使用preload,比使用不匹配的media方法能够更早地开始加载CSS。所以尽管这一标准的支持度还不完善,仍建议优先使用该方法。

    CSS文件压缩

    这应该是最容易想到的一个方法了,通过压缩CSS文件大小来提高页面加载速度。现在的构建工具,如webpack、gulp/grunt、rollup等也都支持CSS压缩功能。压缩后的文件能够明显减小,可以大大降低了浏览器的加载时间。

    CSS层级嵌套最好不要超过3层

    一般情况下,元素的嵌套层级不能超过3级,过度的嵌套会导致代码变得臃肿,沉余,复杂。导致css文件体积变大,造成性能浪费,影响渲染的速度!而且过于依赖HTML文档结构。这样的css样式,维护起来,极度麻烦,如果以后要修改样式,可能要使用!important覆盖。尽量保持简单,不要使用嵌套过多过于复杂的选择器。

    删除无用CSS代码

    一般情况下,会存在这两种无用的CSS代码:一种是不同元素或者其他情况下的重复代码,一种是整个页面内没有生效的CSS代码。

    对于前者,在编写的代码时候,我们应该尽可能地提取公共类,减少重复。对于后者,在不同开发者进行代码维护的过程中,总会产生不再使用的CSS的代码,当然一个人编写时也有可能出现这一问题。而这些无用的CSS代码不仅会增加浏览器的下载量,还会增加浏览器的解析时间,这对性能来说是很大的消耗。所以我们需要找到并去除这些无用代码。

    那么我们如何知道哪些CSS代码是无用代码呢?

    谷歌的Chrome浏览器就有这种开箱即用的功能。只需转到查看>开发人员>开发人员工具,并在最近的版本中打开Sources选项卡,然后打开命令菜单。然后,点击Coverage,在Coverage analysis窗口中高亮显示当前页面上未使用的代码。

    CSS 성능을 최적화하는 방법은 무엇입니까? 최적화 팁 공유

    慎用*通配符

    我们有时候可能会写下面这种代码来消除一些标签的默认样式或统一浏览器对标签渲染的差异化:

    *{
      margin:0;
      padding:0;
    }

    这样虽然代码量少,但它的性能可不是最佳的,我们最好还是写对应的标签选择器:

    body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul{
      margin:0;
      padding:0;
    }

    开发时尽量避免使用通配符选择器

    小图片处理方式

    一般来讲一个网站上肯定会有很多个小图标,对于这些小图标,目前的主流的解决方案有三个,cssSprite(雪碧图)字体图标把图片转成base64

    • cssSprite: 把所有icon图片合成一张png图片,使用时对节点设置宽高,加上bacgroud-position进行背景定位。以背景图方式显展示需要的icon,如果一个网站有20图标,那么就要请求20次,使用cssSprite,只需要请求一次,大大的减少了http请求。缺点就是管理不灵活,如果需要新增一个图标,都需要改合并图片的源文件,图标定位也要规范,不然容易干扰图片之间的定位。
    • 字体图标: 简单粗暴的理解就是把所有的图标当成一个字体处理!这样不用去请求图片。一般是使用class来定义图标,要替换图标时,只需更换样式名,管理方便,语意明确,灵活放大缩小,并且不会造成失真。但是只支持单色的图片。
    • base64: 另一种方案就是把小的icon图片转成base64编码,这样可以不用去请求图片,把base64编码直接整合到js或者css里面,可以防止因为一些相对路径,或者图片被不小删除了等问题导致图片404错误。但是找个方式会生成一大串的base64编码。一般来说,8K以下的图片才转换成base64编码。如果把一张50K的图片转成base64编码,那么会生成超过65000个字符的base64编码,字符的大小就已经是将近70K了!建议就是:8K以下的图片才转换成base64编码。

    避免使用@import

    不建议使用@import主要有以下两点原因:

    • 使用@import引入CSS会影响浏览器的并行下载。使用@import引用的CSS文件只有在引用它的那个css文件被下载、解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析、构建render tree等一系列操作。这就导致浏览器无法并行下载所需的样式文件。

    • 多个@import会导致下载顺序紊乱。在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件先于@import下载,并且打乱甚至破坏@import自身的并行下载

    不要在ID选择器前面进行嵌套其它选择器

    在ID选择器前面嵌套其它选择器纯粹是多余的

    • ID选择器本来就是唯一的而且人家权值那么大,前面嵌套(.content #text)完全是浪费性能。
    • 除了嵌套,在ID选择器前面也不需要加标签或者其它选择器。比如 div#text或者.box#text。这两种方式完全是多余的,理由就是ID在页面就是唯一的。前面加任何东西都是多余的!

    删除不必要的单位和零

    CSS 支持多种单位和数字格式,可以删除尾随和跟随的零,零始终是零,添加维度不会为包含的信息附带任何价值。

    .box {
      padding: .2px;
      margin: 20px;
      avalue: 0;
    }

    优化回流与重绘

    在网站的使用过程中,某些操作会导致样式的改变,这时浏览器需要检测这些改变并重新渲染,其中有些操作所耗费的性能更多。我们都知道,当FPS为60时,用户使用网站时才会感到流畅。这也就是说,我们需要在16.67ms内完成每次渲染相关的所有操作,所以我们要尽量减少耗费更多的操作。

    减少回流与重绘

    合并对DOM样式的修改,采用css class来修改

    const el = document.querySelector(&#39;.box&#39;)
    el.style.margin = &#39;5px&#39;
    el.style.borderRadius = &#39;12px&#39;
    el.style.boxShadow = &#39;1px 3px 4px #ccc&#39;

    建议使用css class

    .update{
      margin: 5px;
      border-dadius: 12px;
      box-shadow: 1px 3px 4px #ccc
    }
    const el = document.querySelector(&#39;.box&#39;)
    el.classList.add(&#39;update&#39;)

    如果需要对DOM进行多次访问,尽量使用局部变量缓存该DOM

    避免使用table布局,可能很⼩的⼀个⼩改动会造成整个table的重新布局

    CSS选择符从右往左匹配查找,避免节点层级过多

    DOM离线处理,减少回流重绘次数

    离线的DOM不属于当前DOM树中的任何一部分,这也就意味着我们对离线DOM处理就不会引起页面的回流与重绘。

    • 使用display: none,上面我们说到了 (display: none) 将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分,之后在该DOM上的操作不会触发回流与重绘,操作完之后再将display属性改为显示,只会触发这一次回流与重绘。

    提醒⏰:visibility : hidden 的元素只对重绘有影响,不影响重排。

    • 通过 documentFragment 创建一个 dom 文档片段,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
    const el = document.querySelector(&#39;.box&#39;)
    const fruits = [&#39;front&#39;, &#39;nanjiu&#39;, &#39;study&#39;, &#39;code&#39;];
    const fragment = document.createDocumentFragment();
    fruits.forEach(item => {
      const li = document.createElement(&#39;li&#39;);
      li.innerHTML = item;
      fragment.appendChild(li);
    });
    el.appendChild(fragment);
    • 克隆节点,修改完再替换原始节点
    const el = document.querySelector(&#39;.box&#39;)
    const fruits = [&#39;front&#39;, &#39;nanjiu&#39;, &#39;study&#39;, &#39;code&#39;];
    const cloneEl = el.cloneNode(true)
    fruits.forEach(item => {
      const li = document.createElement(&#39;li&#39;);
      li.innerHTML = item;
      cloneEl.appendChild(li);
    });
    el.parentElement.replaceChild(cloneEl,el)

    DOM脱离普通文档流

    使用absoultfixed让元素脱离普通文档流,使用绝对定位会使的该元素单独成为渲染树中 body 的一个子元素,重排开销比较小,不会对其它节点造成太多影响。

    CSS3硬件加速(GPU加速)

    使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。

    常见的触发硬件加速的css属性:

    • transform
    • opacity
    • filters
    • Will-change

    将节点设置为图层

    图层能够阻⽌该节点的渲染⾏为影响别的节点。⽐如对于video标签来说,浏览器会⾃动将该节点变为图层。

    具体回流与重绘知识点可以看我这篇文章:https://juejin.cn/post/7064077572132323365

    (学习视频分享:web前端

위 내용은 CSS 성능을 최적화하는 방법은 무엇입니까? 최적화 팁 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제