前端性能优化之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 性能,可以提高网站的性能和用户体验。

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

相关推荐
k***85841 小时前
【SpringBoot】【log】 自定义logback日志配置
android·前端·后端
小满zs1 小时前
Next.js第十章(Proxy)
前端
z***I3943 小时前
JavaScript爬虫应用案例
开发语言·javascript·爬虫
d***9353 小时前
Webpack、Vite区别知多少?
前端·webpack·node.js
清风徐来QCQ3 小时前
javaScript(map,ref,?,forEach,watch)
java·前端·javascript
q***73553 小时前
windows配置永久路由
android·前端·后端
前端布鲁伊3 小时前
再来聊聊,Vue3 项目中 Pinia 的替代方案
前端·面试
星月前端3 小时前
[特殊字符]面向 ArcGIS for JavaScript(4.x)开发者的「坐标系统(CRS / 投影)」全面解读
开发语言·javascript·arcgis
星空的资源小屋4 小时前
永久删除文件利器:Permadelete
java·javascript·人工智能