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能够使页面渲染的开始时间提前,那么是否可以内联所有的CSS呢?答案显然是否定的,这种方式并不适用于内联较大的CSS文件。因为 初始拥塞窗口 存在限制(TCP相关概念,通常是 14.6kB,压缩后大小),如果内联CSS后的文件超出了这一限制,系统就需要在服务器和浏览器之间进行更多次的往返,这样并不能提前页面渲染时间。因此,我们应当只将渲染首屏内容所需的关键CSS内联到HTML中。
    既然已经知道内联首屏关键CSS能够优化性能了,那下一步就是如何确定首屏关键CSS了。显然,我们不需要手动确定哪些内容是首屏关键CSS。Github上有一个项目 Critical CSS,可以将属于首屏的关键样式提取出来,结合自己的构建工具进行使用。当然为了保证正确,大家最好再亲自确认下提取出的内容是否有缺失。
   不过内联CSS有一个缺点,内联之后的CSS不会进行缓存,每次都会重新下载。不过如上所说,如果我们将内联后的文件大小控制在了14.6kb以内,这似乎并不是什么大问题。
使用 Coverage 可以查看首屏未使用的css

二、异步加载css

    CSS会阻塞渲染,在CSS文件请求、下载、解析完成之前,浏览器将不会渲染任何已处理的内容。有时,这种阻塞是必须的,因为我们并不希望在所需的CSS加载之前,浏览器就开始渲染页面。那么将首屏关键CSS内联后,剩余的CSS内容的阻塞渲染就不是必需的了,可以使用外部CSS,并且异步加载。
    4种方式可以实现浏览器异步加载CSS
    1.使用JavaScript动态创建样式表link元素,并插入到DOMconst 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.将link元素的media属性设置为用户浏览器不匹配的媒体类型(或媒体查询)
       如media="print",甚至可以是完全不存在的类型media="noexist"。对浏览器来说,如果样式表不适用于当前媒体类型,其优先级会被放低,会在不阻塞页面渲染的情况下再进行下载。当然,这么做只是为了实现CSS的异步加载,别忘了在文件加载完成之后,将media的值设为screen或all,从而让浏览器开始解析CSS<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all’”>
    3.通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。同样别忘了加载完成之后,将rel改回去。
        <link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet’">
    4.rel=“preload" 这一Web标准指出了如何异步加载资源,包括CSS类资源
        <link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet’">
        Tips:as是必须的。忽略as属性或者错误的as属性会使preload等同于XHR请求,浏览器不知道加载的是什么内容,因此此类资源加载优先级会非常低。as的可选值可以参考上述标准文档。使用preload,比使用不匹配的media方法能够更早地开始加载CSS。所以尽管这一标准的支持度还不完善,仍建议优先使用该方法。可以使用 loadCSS 进行polyfill。

三、文件压缩

    性能优化时有一个最容易想到,也最常使用的方法,那就是文件压缩,这一方案往往效果显著。
    文件的大小会直接影响浏览器的加载速度,这一点在网络较差时表现地尤为明显。相信大家都早已习惯对CSS进行压缩,现在的构建工具,如webpack、gulp/grunt、rollup等也都支持CSS压缩功能。压缩后的文件能够明显减小,可以大大降低了浏览器的加载时间。

四、去除无用的css

    虽然文件压缩能够降低文件大小。但CSS文件压缩通常只会去除无用的空格,这样就限制了CSS文件的压缩比例。那是否还有其他手段来精简CSS呢?答案显然是肯定的,如果压缩后的文件仍然超出了预期的大小,我们可以试着找到并删除代码中无用的CSS。
    一般情况下,会存在这两种无用的CSS代码:一种是不同元素或者其他情况下的重复代码,一种是整个页面内没有生效的CSS代码。对于前者,在编写的代码时候,我们应该尽可能地提取公共类,减少重复。对于后者,在不同开发者进行代码维护的过程中,总会产生不再使用的CSS的代码,当然一个人编写时也有可能出现这一问题。而这些无用的CSS代码不仅会增加浏览器的下载量,还会增加浏览器的解析时间,这对性能来说是很大的消耗。所以我们需要找到并去除这些无用代码。
    当然,如果手动删除这些无用CSS是很低效的。我们可以借助 Uncss 库来进行。Uncss可以用来移除样式表中的无用CSS,并且支持多文件和JavaScript注入的CSS

建议型

1.有选择的使用选择器

    CSS选择器的匹配是从右向左进行的,这一策略导致了不同种类的选择器之间的性能也存在差异。相比于#markdown-content-h3,显然使用#markdown .content h3时,浏览器生成渲染树(render-tree)所要花费的时间更多。因为后者需要先找到DOM中的所有h3元素,再过滤掉祖先元素不是.content的,最后过滤掉.content的祖先不是#markdown的。试想,如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高。
1. 保持简单,不要使用嵌套过多过于复杂的选择器。
2. 通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。
3. 不要使用类选择器和ID选择器修饰元素标签,如h3#markdown-content,这样多此一举,还会降低效率。
4. 不要为了追求速度而放弃可读性与可维护性。
如果大家对于上面这几点还存在疑问,笔者建议大家选择以下几种CSS方法论之一(BEMOOCSSSUITSMACSSITCSS,Enduring CSS等)作为CSS编写规范。使用统一的方法论能够帮助大家形成统一的风格,减少命名冲突,也能避免上述的问题,总之好处多多,如果你还没有使用,就赶快用起来吧。
    Tips:为什么CSS选择器是从右向左匹配的?
    CSS中更多的选择器是不会匹配的,所以在考虑性能问题时,需要考虑的是如何在选择器不匹配时提升效率。从右向左匹配就是为了达成这一目的的,通过这一策略能够使得CSS选择器在不匹配的时候效率更高。这样想来,在匹配时多耗费一些性能也能够想的通了。

2.减少使用昂贵的属性

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

3.不要使用@import引入css

    不建议使用@import主要有以下两点原因。
    1.首先,使用@import引入CSS会影响浏览器的并行下载。使用@import引用的CSS文件只有在引用它的那个css文件被下载、解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析、构建render tree等一系列操作。这就导致浏览器无法并行下载所需的样式文件。
    2.其次,多个@import会导致下载顺序紊乱。在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件先于@import下载,并且打乱甚至破坏@import自身的并行下载。
    所以不要使用这一方法,使用link标签就行了。

4.优化重排和重绘

FPS(每秒传输帧数(Frames Per Second))为60时,用户使用网站时才会感到流畅。这也就是说,我们需要在16.67ms内完成每次渲染相关的所有操作,所以我们要尽量减少耗费更多的操作。
        1.减少重排
                1. 改变font-size和font-family
                2. 改变元素的内外边距
                3. 通过JS改变CSS4. 通过JS获取DOM元素的位置相关属性(如width/height/left等)
                5. CSS伪类激活
                6. 滚动滚动条或者改变窗口大小
                Tips:  通过 CSS Trigger 查询哪些属性会触发重排与重绘.
            某些CSS属性具有更好的重排性能。如使用Flex时,比使用inline-block和float时重排更快,所以在布局时可以优先考虑Flex。
        2.避免不必要的重绘
                当元素的外观(如color,background,visibility等属性)发生改变时,会触发重绘。在网站的使用过程中,重绘是无法避免的。不过,浏览器对此做了优化,它会将多次的重排、重绘操作合并为一次执行。不过我们仍需要避免不必要的重绘,如页面滚动时触发的hover事件,可以在滚动的时候禁用hover事件,这样页面在滚动时会更加流畅。我们编写的CSS中动画相关的代码越来越多,我们已经习惯于使用动画来提升用户体验。我们在编写动画时,也应当参考上述内容,减少重绘重排的触发。我们还可以通过 硬件加速 和 will-change 来提升动画性能。
                可以通过Chrome的开发者工具进行CPU降速(performance),然后再进行相关的测试。如果需要在移动端访问的,最好将速度限制更低,因为移动端的性能往往更差。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值