CSS如何提高页面的性能

作为开发人员,给自己应用提供更快的访问速度,提供很好的用户体验是必备的基础技能。那我们今天就来和大家聊聊,本文介绍一些在CSS方面有哪些技巧可以帮助我们来提高Web页面的渲染速度和性能优化的方案。

一、内联首屏关键CSS

渲染的大概流程:

加载HTML资源
解析HTML
加载CSS资源,同时构建DOM树
解析CSS,同时渲染DOM树
当CSS文件过大,就会停留在第3步,网速慢时,打开网站的时候经常遇到没有样式的情况。

所以我们需要先加载部分CSS(首屏需要用到的CSS),其他优先级比较低的CSS就以异步的方式加载。

将渲染首屏内容所需的关键CSS内联到HTML中,能使CSS更快速地下载。在HTML下载完成之后就能渲染了,页面渲染的时间提前,从而缩短首屏渲染时间;
其余CSS使用外部CSS文件,在HTML文档下载完成后再下载它们。这样能够启用缓存,除此之外还可以异步加载它们。

缺点:内联之后的CSS不会进行缓存,每次都会重新下载。

二、异步加载CSS

CSS会阻塞渲染,在CSS文件请求、下载、解析完成之前,浏览器将不会渲染任何已处理的内容。有时,这种阻塞是必须的,因为我们并不希望在所需的CSS加载之前,浏览器就开始渲染页面。那么将首屏关键CSS内联后,剩余的CSS内容的阻塞渲染就不是必需的了,可以使用外部CSS,并且异步加载。

异步加载css方式有下面几种:

1.js动态创建样式表link元素,并插入到DOM中

// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );

2.设置media属性

将link元素的media属性设置为用户浏览器不匹配的媒体类型(或媒体查询),如media=“print”,甚至可以是完全不存在的类型media=“noexist”。对浏览器来说,如果样式表不适用于当前媒体类型,其优先级会被放低,会在不阻塞页面渲染的情况下再进行下载。

<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">

当然,这么做只是为了实现CSS的异步加载,别忘了在文件加载完成之后,将media的值设为screen或all,从而让浏览器开始解析CSS。

3.设置rel属性
通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。同样别忘了加载完成之后,将rel改回去。

<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
  1. rel=“preload”
<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">

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

三、文件压缩

文件的大小会直接影响浏览器的加载速度,现在的构建webpack、gulp/grunt、rollup等也都支持CSS压缩功能。压缩后的文件能够明显减小,可以大大降低了浏览器的加载时间。

如:extract-text-webpack-plugin

四、去除无用CSS

虽然文件压缩能够降低文件大小,但css文件压缩通常只会去除无用的空格,这样就限制css文件的压缩比例。如果压缩后的文件仍然超过来预期的大小,可以试着找到并删除代码中无用的css。
一般情况下,会存在这两种无用的CSS代码:

  • 不同元素或者其他情况下的重复代码,
  • 整个页面内没有生效的CSS代码

巧妙运用css的继承机制,如果父节点定义了,子节点就无需定义。

五、有选择地使用选择器

CSS选择器的匹配是从右向左进行的,这一策略导致了不同种类的选择器之间的性能也存在差异。

CSS中更多的选择器是不会匹配的,所以在考虑性能问题时,需要考虑的是如何在选择器不匹配时提升效率。从右向左匹配就是为了达成这一目的。

相比于#a-b-c,显然使用#a .b c时,浏览器生成渲染树(render-tree)所要花费的时间更多。因为后者需要先找到DOM中的所有c元素,再过滤掉祖先元素不是.b的,最后过滤掉.b的祖先不是#a的。嵌套的层级更多,要花费的时间越久。

  1. 不要使用嵌套过多过于复杂的选择器。
  2. 通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。
  3. 不要使用类选择器和ID选择器修饰元素标签,如h3#markdown-content
    (ID本来就是唯一的而且权限值大,嵌套完全是浪费性能。)

六、减少使用昂贵的属性

在浏览器绘制屏幕时,所有需要浏览器进行操作或计算的属性相对而言都需要花费更大的代价。当页面发生重绘时,它们会降低浏览器的渲染性能。尽量减少使用昂贵属性,如box-shadow/border-radius/filter/透明度/:nth-child等。

七、优化重排与重绘

1. 减少重排

重排会导致浏览器重新计算整个文档,重新构建渲染树,这一过程会降低浏览器的渲染速度。

会引起重排的操作:

  • 添加或者删除可见的DOM元素
  • 元素位置改变
  • 元素尺寸改变
  • 元素内容改变(例如:一个文本被另一个不同尺寸的图片替代)
  • 页面渲染初始化(这个无法避免)
  • 浏览器窗口尺寸改变
  • CSS伪类激活

常见重排元素:

  • 大小有关的 width,height,padding,margin,border-width,border,min-height
  • 布局有关的 display,top,position,float,left,right,bottom
  • 字体有关的 font-size,text-align,font-weight,font-family,line-height,white-space,vertical-align
  • 隐藏有关的 overflow,overflow-x,overflow-y

使用以下步骤可以避免页面中的大部分重排:

  1. 使用绝对位置定位页面上的动画元素,将其脱离文档流
  2. 让元素动起来。当它扩大时,会临时覆盖部分页面。但这只是页面一个小区域的重绘过程,不会产生重排并重绘页面的大部分内容。
  3. 当动画结束时恢复定位,从而只会下移一次文档的其他元素
  4. 使用Flex时,比使用inline-block和float时重排更快,所以在布局时可以优先考虑Flex。

2.避免不必要的重绘

在网站的使用过程中,重绘是无法避免的。不过,浏览器对此做了优化,它会将多次的重排、重绘操作合并为一次执行。不过我们仍需要避免不必要的重绘,如页面滚动时触发的hover事件,可以在滚动的时候禁用hover事件,这样页面在滚动时会更加流畅。

当元素的外观(如color,background,visibility等属性)发生改变时,会触发重绘。

八、让元素及其内容尽可能独立于文档树的其余部分

contain属性允许我们指定特定的DOM元素和它的子元素,让它们能够独立于整个DOM树结构之外。目的是能够让浏览器有能力只对部分元素进行重绘、重排,而不必每次针对整个页面。即,允许浏览器针对DOM的有限区域而不是整个页面重新计算布局,样式,绘画,大小或它们的任意组合。

在实际使用的时候,我们可以通过contain设置下面五个值中的某一个来规定元素以何种方式独立于文档树:

  1. layout :该值表示元素的内部布局不受外部的任何影响,同时该元素以及其内容也不会影响以上级;容器的后代不应该导致其容器外元素的布局改变,反之亦然
  2. paint :该值表示元素的子级不能在该元素的范围外显示,该元素不会有任何内容溢出(或者即使溢出了,也不会被显示);容器的内容将永远不会绘制超出容器的尺寸,如果容器是模糊的,那么就根本不会绘制内容
  3. size :该值表示元素盒子的大小是独立于其内容,也就是说在计算该元素盒子大小的时候是会忽略其子元素;当其内容发生变化时,该容器不应导致页面上的位置移动
  4. content :该值是contain: layout paint的简写
  5. strict :该值是contain: layout paint size的简写

九、避免使用@import

使用@import引入css会影响浏览器的并行下载。使用@import引用的css文件只有在引用它的那个css文件被下载,解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析,构建render tree等一系列操作,这就导致浏览器无法并行下载,外部的css文件中使用@import会使得页面在加载时增加额外的延迟。
最好还是使用link标签。

十、开启GPU渲染动画

浏览器针对处理CSS动画和不会很好地触发重排(因此也导致绘)的动画属性进行了优化。

为了提高性能,可以将动画的节点从主线程移到GPU上。将导致合成的属性包括 3D transforms (transform: translateZ(), rotate3d(),等),animatingtransformopacity, position: fixed,will-change,和 filter。一些元素,例如 , 和 ,也位于各自的图层上。 将元素提升为图层(也称为合成)时,动画转换属性将在GPU中完成,从而改善性能,尤其是在移动设备上。

十一、合并css文件

如果页面加载10个css文件,每个文件1k,那么也要比只加载一个100k的css文件慢。

更多优化方案参考:# 仅使用CSS提高页面渲染速度

原文链接:https://juejin.cn/post/7237127933404233788 作者:白哥学前端

(0)
上一篇 2023年5月25日 上午11:17
下一篇 2023年5月26日 上午10:05

相关推荐

发表回复

登录后才能评论