提升 CSS 性能和文件大小——深入指南
目录
什么导致 CSS 变慢?
文件大小
文件越大,下载和解析时间就越长。就是这么简单。
CSS渲染
为了了解 CSS 渲染瓶颈可能出现的位置,我们需要查看渲染管道步骤:
1. 样式——确定哪些 CSS 规则适用于 HTML 文档中的哪些元素。
2. 布局- 确定元素在屏幕上的位置以及占用的空间。CSS 属性:position
、top
、left
、right
、bottom
等。
3. Paint - 确定视觉元素。CSS 属性:color
、border
、background-color
等。
4. 复合- 在屏幕上绘制图层。CSS 属性:opacity
和transform
。
CSS 在动画和过渡方面提供了丰富的选项。我们可以在很多 CSS 属性上创建过渡。有些过渡和动画可以利用 GPU 并表现出色,带来流畅的 60 FPS(每秒帧数)体验。另一方面,有些 CSS 属性在动画时可能会导致 FPS 较低且动画不流畅。
任何步骤的更改或更新都会导致后续步骤的更新。我们可以看到, Layout 步骤的动画开销最高,而 Composite 步骤的动画开销最低。
减少 CSS 文件大小
通过减小 CSS 文件的大小,我们可以减少下载时间和加载时间。即使在 CSS 工作完成后,也可以进行一些与文件大小相关的改进,这是一种非常有效的优化。为了最大限度地提高效率,最好从一开始就牢记并应用这些改进。
最小化
CSS 文件压缩很容易实现,并且是提升 CSS 性能的第一步。压缩会删除 CSS 文件内部的格式化字符(空格、换行符等),这些字符只对我们有用(使代码更易读)。
/* Non-minified code */
.card {
padding: 1rem;
background-color: #aaa;
}
/* Minified code */
.card{padding:1rem;background-color:#aaa}
市面上有很多在线、自动化和 CDN 的“压缩”工具可以帮助你进行 CSS 压缩。以下是 CSS 压缩工具:
优化
等一下……我们已经压缩了 CSS 文件。它不是已经优化了吗?
从技术上来说确实如此。CSS 优化指的是删除不必要的 CSS 或重新格式化 CSS 属性以减少字符数量。与压缩不同,这种改进无法在 CDN 上完成,必须在代码编译时(使用 Webpack 或 Gulp 等工具)完成。
我们来看下面的例子。
/* Unoptimized CSS */
.card {
background-color: #aaaaaa;
padding: 0.5rem 1rem 0.5rem 1rem;
}
.card__content {
padding: 0.5rem 1rem 0.5rem 1rem;
}
乍一看,这看起来就像任何人都会写且不假思索的常规 CSS。但是,可以进行一些优化以减少字符数量。
/* Optimized CSS */
.card {
background-color:#aaa;
}
.card,
.card__content {
padding:.5rem 1rem;
}
我们将字符数从 132 个减少到了 85 个(减少了 35%)。让我们应用缩小功能并查看最终结果。
/* Optimized CSS with minification */
.card{background-color:#aaa}.card,.card__content{padding:.5rem 1rem}
我们将字符数从 132 个减少到 68 个(总共减少了 48%)。
您可以看到优化对 CSS 的影响有多大。这种减少是由于删除了 DRY 代码,而在这个简单的示例中,DRY 代码是可以避免的。看看包含数千行代码且经常更改的 CSS 文件(尤其是将其拆分成多个文件后),我们可以轻松地降低代码的 DRY 要求。幸运的是,有一些工具可以帮助我们优化代码并保持 DRY 规范。
在上一节中,我们提到了用于优化 CSS 的众多工具中的两个:
压缩
压缩在服务器端完成。它使用 gzip 或 Brotli 进行压缩并进一步减小文件大小,以减少文件下载时间。
这个主题非常广泛,涵盖的文件类型远不止 CSS。如果你对实现服务器端压缩感兴趣, CSS tricks 写了一篇关于这个主题的很棒的文章。
还需要注意的是,大多数 CDN 服务都提供开箱即用的压缩选项。
CSS结构
拥有良好的 CSS 结构并运用各种 CSS 最佳实践,在压缩后也能减小 CSS 文件的大小。例如,使用 BEM 和低优先级的类选择器,可以减少文件中的字符数,从而减小文件大小。
我在之前的一篇文章中介绍过 CSS 结构的改进。遵循这些 CSS 原则,你将拥有一个结构良好、遵循 DRY 原则的 CSS 文件,并为优化和压缩奠定良好的基础。
提高 CSS 动画性能
过渡和动画
我们已经介绍了 CSS 渲染管线以及导致动画缓慢的原因。所以,基本上,布局步骤的动画开销最高,而复合步骤的动画开销最低。
如果我们查看导致复合层更新的 CSS 属性,它们是transform
和opacity
。这两个属性使用硬件 (GPU) 加速,从而实现非常高效的更新。
如果将过渡效果应用于位置属性(例如top
或left
),动画性能会很差,因为我们正在更新布局步骤,这会强制Paint和Composite也进行更新。将位置 CSS 属性替换为transform
并在其上使用过渡效果后,我们只会更新Composite步骤,从而实现流畅的动画。
将元素提升到复合层
我们并不局限于只使用transform
和opacity
来实现流畅的动画。CSS 提供了多种方法将元素“提升”到复合层,以告知浏览器该元素的 Paint CSS 属性将经常更新。
实现此目的的 hack 且“老办法”是添加backface-visibility: hidden;
或transform: translate3d(0,0,0);
。在大多数情况下,这些属性不会以任何方式影响您的元素(如果它们不覆盖任何内容),但它们会让浏览器将元素移动到复合层,从而显著提高动画性能。
.example {
width: 20rem;
height: 20rem;
background-color: #aaa;
border-radius: 0;
backface-visibility: hidden;
transition: border-radius 0.3s ease-in-out;
}
.example:hover {
border-radius: 50%;
}
will-change 属性
告诉浏览器哪个元素需要更新(就 CSS 渲染而言)的一种现代方式是设置will-change
属性。
.card {
background-color: #aaa;
transition: background-color 0.3s ease-in-out;
will-change: background-color;
}
.card:hover {
will-change: background-color;
}
.card:active {
background-color: #bbb;
}
使用时需要注意以下几点will-change
:
- 不要将 will-change 应用于太多元素。
- 谨慎使用
- 不要对元素应用 will-change 来执行过早优化。
- 给予它足够的时间来发挥作用。
包含属性
CSScontain
属性代表了 CSS 渲染管道优化的未来。目前,它仅受部分浏览器支持。它允许我们指定元素的子树与页面的其余部分无关。这使得浏览器可以针对 DOM 的有限区域(而非整个页面)重新计算布局、样式、绘制、大小或其任意组合。
contain: none; /* No optimization */
contain: strict; /* Equivalent to contain: layout paint size style */
contain: content; /* Equivalent to contain: layout paint style */
contain: size; /* component size is set and no descendant will modify its size. */
contain: layout; /* changes to any descendant of this element will not affect the layout of any outside element and vice versa. */
contain: style; /* descendant’s styles will not affect outside elements. */
contain: paint; /* you specify that no descendant will display outside the elements bounds. Similar to overflow: hidden; */
使用 CSS 属性的示例contain
:
.box {
contain: layout size; /* Won't change size and won't affect layout */
}
<div class="box">
<div class="box__content">...</div>
</div>
奖励:CSS 性能技巧
避免使用@import
@import
CSS 属性用于将一个 CSS 文件包含在另一个 CSS 文件中。问题在于,这些文件会依次加载,而不是像推荐的 HTML 样式表加载方式那样并行加载。
如果有多个样式表,请使用 HTTP/2
HTTP/2 在加载大量小文件时带来显著的性能提升。如果您使用的 CSS 结构会产生多个 CSS 样式表(例如单个屏幕、模块、组件等),那么 HTTP/2 是一个理想的解决方案。
如果您不使用 HTTP/2,建议将所有 CSS 文件合并为一个 CSS 文件。
注意“昂贵”的房产
有些属性会占用更多资源,并增加渲染时间。如果您打算支持处理能力较低的设备,了解以下属性将大有裨益:
border-radius
box-shadow
filter
position: fixed
*
:nth-child
通过 CDN 提供 CSS 文件
通过 CDN 提供图片、CSS、JS 等静态文件可以缩短下载时间。此外,一些 CDN 服务提供基本的压缩和优化选项,因此如果您的代码尚未压缩,可以轻松提升性能。
保持选择器简单
使用简单的类选择器(考虑使用 BEM 和 OOCSS 或其他风格及其组合)可以提高网站渲染的性能,尤其是在处理能力较低的设备上。我在之前的一篇文章中更深入地讨论过这个主题:
这些文章都是咖啡带来的灵感。所以,如果你喜欢我的文章,觉得它有用,不妨请我喝杯咖啡!我会非常感激的。
感谢您花时间阅读这篇文章。如果您觉得它有用,请点赞 ❤️ 或 🦄,分享并评论。
文章来源:https://dev.to/prototyp/improving-css-performance-and-file-size-an-in-deep-guide-4mb5