前端性能优化之CSS篇

1、前言

当涉及到网站的性能优化时,CSS 的优化是一个非常重要的方面。如果你的 CSS 太复杂,那么你的网站可能会像一个慢吞吞的乌龟 一样缓慢地加载和渲染,影响用户的留存网站的转化率 以及网站的体验和传播等,所以对于 CSS 优化还是非常需要的,本文将介绍一些 CSS 性能优化的技巧,帮助你在编写 CSS 代码时提高性能。

2、前置知识

2.1 CSS 解析规则

我们一般书写 CSS 选择器都是从左往右书写的,所以自然就会以为 CSS 选择器是从左往右去匹配渲染的,但其实不是这样的,CSS 选择器是从右往左去匹配的

css 复制代码
.header div span { 
  color: red;
}

比如上面的 CSS 样式匹配查找过程是这样的:

  1. 先找到所有的 span 元素。
  2. 从第一个 span 元素开始,沿着 span 元素的父级元素查到 div,最后沿着 div 的父级元素找到所有的 .header,找到满足条件的节点就加入到结果集中。

2.2 CSS 的加载过程

简述浏览器的渲染过程:在拿到 html 文件后,浏览器会调用 html 解析器解析 html 文件,构建 DOM 树和 CSSOM 树,然后 DOM 树和 CSSOM 树合并成渲染树,最后浏览器会根据渲染树进行布局和绘制,最终将页面呈现给用户。

CSSOM 的构建 :当浏览器解析 html 文档时,如果遇到 <link><style> 标签,会开始下载和解析 CSS 文件,构建 CSSOM。在 CSSOM 构建完成之前,浏览器不会渲染任何已处理的内容,即使DOM已经解析完毕。

  • CSS 不会阻塞 DOM 的解析,但会阻塞 DOM 的渲染。
  • CSS 不会阻塞 Javascript 的下载,但会阻塞 JavaScript 的执行,因为 JavaScript 可以操作样式,所以需要等 CSSOM 构建完成之后,才能执行 JavaScript

所以从这里就可以得到以下优化思路:。

  • 将一些体积小的首屏关键 CSS 内联到 html 文件中,加快首屏渲染速度。
  • 将 CSS 放在 <head> 中,确保尽早加载。
  • 使用媒体查询(如 media="print")使 CSS 非阻塞渲染。
  • 在生产环境中,考虑使用 preload(如 <link rel="preload" as="style">)在不阻塞渲染的情况下加载非首屏的 CSS 资源。

2.3 CSS 权重优先级

CSS 选择器类型的优先级从低往高依次是:

  1. 类型选择器 (比如 h1)和伪元素选择器 (比如 ::before)。
  2. 类选择器 (比如 .header)、属性选择器 (比如 [type="checkbox"])和伪类选择器 (比如 :hover)。
  3. ID 选择器 (比如 #box)。
  4. !important:优先级最高。

2、CSS 加载性能优化

2.1. 提取公共的 CSS 文件

如果使用webpack进行项目打包,在打包阶段可以使用mini-css-extract-plugin提取公共 CSS 文件,便于缓存以及减少 CSS 请求次数。

2.2 避免使用 @import

  • 使用 @import 会阻塞浏览器的并行下载,导致加载速度变慢。
  • 多个 @import 会导致下载顺序紊乱。

2.3 压缩 CSS 文件

压缩 CSS 文件可以减小文件大小,从而加快加载速度。比如可以用optimize-css-assets-webpack-plugin配合mini-css-extract-plugin使用来优化和压缩 CSS 文件。

2.4 使用浏览器缓存

可以使用浏览器缓存来缓存 CSS 文件,从而在页面加载时加快速度。可以设置适当的缓存时间来确保文件在必要时能够更新。

2.5 使用 CDN 加速

  • 使用 CDN(内容分发网络) 可以将 CSS 文件分发到全国各个 CDN 节点的服务器上,用户可以就近下载,从而加快加载速度,也可以减少自己服务器的负载。
  • 如果静态资源很多,可以准备多个静态服务器域名,比如域名是 static.xx.com,做成支持 static0-5 的 6 个域名, 也就是 static0.xx.com、static1.xx.com、static2.xx.com...,每次请求时随机选一个域名地址进行请求,这样可以绕过浏览器同域名的连接数限制(一般是限制 6 个),6 个域名就可以同时发送 36 个连接请求。当然,这个域名个数不是越多越好,太分散的话又会涉及到多域名无法缓存静态资源的问题。

2.6 使用 CSS Sprite

CSS Sprite 技术就是我们常说的雪碧图 ,通过将多张小图标拼接成一张大图,能有效的减少HTTP请求数量以达到加速显示内容的技术。

2.7 CSS 样式抽离和去除无用 CSS

  • 平时开发过程中可以将一些可复用的 CSS 抽离到一个单独文件中,减少 CSS 代码冗余。
  • 在打包构建时可以利用一些插件去除没有用到的 CSS,相当于对 CSS 进行 Tree shaking,减少打包后体积。

2.8 合理使用内嵌 CSS

内嵌CSS 也就是通过元素的 style 来书写行内样式,比如 <div style="color: red"></div>,它的优缺点如下:

优点

  • 与使用 link 标签相比,可以减少 CSS 的 http 请求量。

缺点

  • 增加 html 文件的体积。
  • 使用 link 标签能很好的利用浏览器的缓存,而内联样式放在 html 里面,能否使用缓存需要看 html 文件的缓存策略。

综合它的优缺点,我们可以选择将一些体积小的首屏关键 CSS 内联到 html 文件中,加快首屏渲染速度。

3、CSS 选择器性能优化

3.1 避免使用通配符选择器

通配符选择器*符号可以匹配任何元素,但是这会导致浏览器需要遍历整个文档树来查找匹配的元素,从而降低性能。

3.2 使用子选择器代替后代选择器

后代选择器(如 .parent .child)会检查所有后代元素,而子选择器(如 .parent > .child)只检查直接子元素,匹配范围更小,性能更好。

3.3 优先使用类(Class)和 ID 选择器

类选择器(如 .box)和 ID 选择器(如 #box)匹配速度更快,因为它们直接指向特定元素。避免标签选择器(如 div)或属性选择器(如 [type="text"]),后者匹配更加宽泛,效率较低,尤其在大型 DOM 中。

3.4 避免深层嵌套的选择器

前面也说过,CSS 选择器需要从右往左去匹配的,嵌套的选择器如 .header div ul li a,因为浏览器需要遍历更多 DOM 节点。建议限制选择器深度在 3 层以内,使用更直接的类或 ID 选择器,如 .box。这能减少匹配时间。或者使用 BEM 命名规范,比如 .block__element--modifier,提高匹配效率。

另外在使用 ID 选择器的时候,前面就需要加上父级的选择器,比如不推荐用 .box #content,推荐用 #content

4、CSS 属性性能优化

4.1 避免使用过于复杂的属性

过于复杂的属性会增加浏览器的渲染负担,从而降低性能。应该尽量使用简单的属性来实现需要的样式效果,比如下面这些属性:

  • box-shadow :box-shadow 属性可以实现盒子的阴影效果,但是它会增加浏览器的计算和渲染成本。如果要实现一个简单的边框效果,可以使用 border 属性来替代。
css 复制代码
/* 不推荐使用 */
.box {
  box-shadow: 2px 2px 2px #888;
}

/* 推荐使用 */
.box {
  border: 1px solid #888;
}
  • filter :filter 属性可以实现图像的滤镜效果,但是它会增加浏览器的计算和渲染成本。如果要实现一个简单的颜色变换效果,可以使用 background-color 属性来替代。
css 复制代码
/* 不推荐使用 */
.box {
  filter: grayscale(50%);
}

/* 推荐使用 */
.box {
  background-color: #ccc;
}

不过需要注意的是,这些替代方案可能会有一些局限性,无法完全取代原来的属性。因此,在使用这些替代方案时,需要根据具体的需求和情况进行选择。

4.2 避免使用不必要的属性

不必要的属性会增加 CSS 文件的大小,从而降低加载速度。应该尽量避免使用不必要的属性。

4.3 避免使用 !important

!important 会覆盖其他样式,从而增加渲染时间。而且它不容易被替换或覆盖,后期可维护性也比较差,更好的方式使用更具体、更准确的选择器来定义样式。

5、CSS 动画性能优化

5.1 使用 transform 和 opacity 属性来进行动画

使用 transformopacity 属性可以减少浏览器的渲染负担,从而提高性能。

5.2 避免使用过于复杂的动画效果

过于复杂的动画效果会增加浏览器的渲染负担,从而降低性能。应该尽量使用简单的动画效果。

5.3 在动画中使用 will-change 属性

will-change 属性可以告诉浏览器哪些属性将要被改变,从而提前进行优化,减少渲染负担。

5.4 使用 requestAnimationFrame() 函数来优化动画

requestAnimationFrame() 函数可以在浏览器下一次渲染之前执行代码,从而减少渲染负担,提高性能。

6、CSS 渲染性能优化

6.1 使用 class 合并 DOM 的修改

比如我们需要根据不同情况给一个元素添加不同的样式,可能会写出如下的代码:

js 复制代码
const el = document.querySelector('.box');
if (isHover) {
  el.style.color = 'red';
  el.style.background = 'blue';
} else {
  el.style.color = 'blue';
  el.style.background = 'red';
}

这时候我们可以定义两个 class 类,然后直接切换类名即可。

js 复制代码
const el = document.querySelector('.box');
if (isHover) {
  el.classList.remove('normal');
  el.classList.add('hover');
} else {
  el.classList.remove('hover');
  el.classList.add('normal');
}

6.2 让 DOM 元素脱离文档流

使用 absoulte 或者 fixed 定位让 DOM 元素脱离文档流,这样在修改 DOM 元素的时候不会影响到其他 DOM 元素的布局,从而提高渲染性能。

7、总结

本文主要通过CSS 加载性能优化CSS 选择器性能优化CSS 属性性能优化CSS 动画性能优化CSS 渲染性能优化这些方向介绍了 CSS 的性能优化技巧。通过优化 CSS 性能,可以提高网站的性能和用户体验。

在实际开发中,可根据实际业务场景和需要去进行优化。

相关推荐
天天扭码14 分钟前
前端如何实现RAG?一文带你速通,使用RAG实现长期记忆
前端·node.js·ai编程
Luna-player1 小时前
在前端中,<a> 标签的 href=“javascript:;“ 这个是什么意思
开发语言·前端·javascript
lionliu05191 小时前
js的扩展运算符的理解
前端·javascript·vue.js
小草cys1 小时前
项目7-七彩天气app任务7.4.2“关于”弹窗
开发语言·前端·javascript
奇舞精选1 小时前
GELab-Zero 技术解析:当豆包联手中兴,开源界如何守住端侧 AI 的“最后防线”?
前端·aigc
奇舞精选1 小时前
Vercel AI SDK:构建现代 Web AI 应用指南
前端·aigc
神仙别闹2 小时前
基于C语言实现B树存储的图书管理系统
c语言·前端·b树
郝学胜-神的一滴2 小时前
Python数据模型:深入解析及其对Python生态的影响
开发语言·网络·python·程序人生·性能优化
玄魂2 小时前
如何查看、生成 github 开源项目star 图表
前端·开源·echarts
前端一小卒3 小时前
一个看似“送分”的需求为何翻车?——前端状态机实战指南
前端·javascript·面试