3. 针对终点资源的处理
CSS 不太可能是性能问题的罪魁祸首。然而,它可能加载一些重量级的资源,这些资源可以在几分钟内进行优化。例如:
- 在服务器上启用
HTTP/2
和GZIP
压缩 - 使用
CDN
来增加同时的HTTP
连接数量,并将文件复制到世界各地的其他位置 - 删除未使用的文件
Image
通常是页面负重的最大原因,但许多网站未能有效优化:
- 调整位图图像的大小。
- 确保使用适当的文件格式。通常,照片最适合使用
WebP
格式,矢量图像使用SVG
格式,其他内容使用PNG
格式。 - 使用图像工具通过删除元数据和增加压缩因子来减小文件大小。
图像数据的
xKB
不等于 CSS 代码的xKB
。二进制图像可以并行下载,并且在页面上放置时需要很少的处理。CSS 阻止渲染,浏览器在继续之前必须将其解析成对象模型。
4. 用 CSS 效果替换图片
很少需要为边框、阴影、圆角、渐变和一些几何形状使用背景图像
。使用 CSS
代码定义image
所需的带宽要少得多,并且以后更容易进行修改或动画处理。
以下是如何使用CSS代码来创建圆角效果和渐变效果:
- 圆角效果:
.rounded-box { width: 200px; height: 150px; background-color: #f0f0f0; border-radius: 10px; /* 使用border-radius属性创建圆角效果 */ }
- 渐变效果:
.gradient-background { width: 300px; height: 200px; /* 使用linear-gradient()函数创建渐变背景 */ background: linear-gradient(to bottom, #ff9900, #ff3300); }
通过上述示例,我们可以看到如何使用CSS属性和函数来创建圆角效果和渐变效果,而无需使用背景图像。这种方法不仅减少了网络请求和带宽消耗,还使样式更易于修改和维护。
类似地,对于其他元素(如阴影、边框等),我们也可以使用CSS的相关属性来实现样式效果,而无需依赖背景图像。这种做法有助于提高性能并保持代码的可维护性。
5. 删除不必要的字体
诸如Google Fonts
之类的服务使将自定义字体添加到任何页面变得容易。然而,一两行代码可能会检索数百KB的字体数据。建议如下:
- 只使用我们所需要的字体。
- 仅加载所需的字重和样式,例如正常字体、400字重、无斜体。
- 在可能的情况下,限制字符集。
- 考虑使用
可变字体
,它通过插值定义多个字重和样式,从而使文件更小。 - 考虑使用操作系统字体。
上面的有些方式比较简单,就不展开说明,我们来简单介绍一下--可变字体.
可变字体(Variable Fonts)
可变字体(Variable Fonts)是一种字体技术,允许在单个字体文件中包含多个字重(粗细)和字形(样式)的变化。通过调整不同的轴(Axis
),我们可以实时控制字体的多个属性,如粗细、宽度、倾斜度等,从而创造出更加灵活和多样化的字体效果。这种技术使得字体的定制和排版变得更加自由和创意。
选择一个技术,首先需要看这个技术的是否被大众采纳. 我们通过Can I use进行查看,发现它是被大众认可的.
下面是一个示例,演示了如何使用可变字体:
/* 引入可变字体 */ @font-face { font-family: 'CustomVariableFont'; src: url('path-to-font/custom-variable-font.woff2') format('woff2-variations'); } /* 应用可变字体 */ body { font-family: 'CustomVariableFont', sans-serif; font-weight: 300; /* 字重为轻 */ font-variation-settings: 'wght' 700, 'slnt' -10, 'wdth' 100; /* 控制字体属性 */ } h1 { font-family: 'CustomVariableFont', sans-serif; font-weight: 700; /* 字重为粗 */ font-variation-settings: 'wght' 700, 'slnt' 0, 'wdth' 100; /* 控制字体属性 */ }
在上面的示例中,我们首先通过@font-face
规则引入了可变字体文件。然后,我们使用font-family
来定义字体系列,并通过font-weight
和font-variation-settings
来控制字体的属性。在font-variation-settings
中,我们可以指定不同轴的属性值,如'wght'
代表字重,'slnt'
代表倾斜度,'wdth'
代表宽度。这些属性值可以根据具体的字体文件和需求进行调整。
如果想了解更多关于可变字体,可以参考google 文档
6. 避免使用 @import
@import
是一种CSS规则,用于在一个CSS文件中引入另一个CSS文件。通过使用@import
,我们可以将多个CSS文件合并成一个文件,以便更好地组织和管理样式。。例如:
/* main.css */ @import url("base.css"); @import url("layout.css"); @import url("carousel.css");
这似乎是一种加载较小组件和字体的合理方式。但实际上不是。@import
规则可以嵌套,因此浏览器必须逐个加载和解析每个文件。
虽然@import
在代码模块化(将样式分成多个文件,每个文件负责不同的样式部分,使得代码更模块化和易于维护)和组织性(可以更好地组织和管理代码,将相关的样式放在一起,提高代码的可读性和可维护性)。上有很高的建树.
但是呢,它的缺点也很明显.
- 性能问题:使用
@import
会导致多个HTTP请求,每个@import
都会阻塞页面的加载,影响页面性能。这是因为浏览器需要等到导入的样式加载完毕后才能继续加载页面的其余部分。 - 阻塞渲染:由于
@import
会阻塞页面的加载,导致页面的渲染时间延长,用户可能会看到白屏。
替代方案
<link>
标签:使用<link>
标签在HTML的<head>
部分直接引入外部CSS文件。这种方法不会阻塞页面加载,同时可以并行加载多个CSS文件。
<link rel="stylesheet" href="base.css"> <link rel="stylesheet" href="layout.css"> <link rel="stylesheet" href="carousel.css">
- CSS预处理器:使用CSS预处理器(如Sass、Less、Stylus)来管理样式文件,通过预处理器的导入功能将多个部分的样式文件合并成一个,最终编译为一个CSS文件。
- 如果在使用了预处理器后,还想使用类似
@import
的功能,我们可以使用@use
(在Sass中使用)
- 模块化构建工具:使用模块化构建工具(如Webpack、vite、Rollup)来管理样式,通过构建工具的功能将多个样式文件合并、压缩,然后输出为一个优化后的CSS文件
7. 合并CSS
大多数构建工具(如Webpack
、Vite
、Rollup
)允许我们将所有部分组合成一个大的CSS文件,其中不必要的空格、注释和字符都被删除了。
构建工具
Webpack 5 和 Vite 都是现代前端构建工具,它们都能够有效地管理样式。以下是它们分别管理样式的简要描述和示例代码:
Webpack 5 管理样式:
Webpack 5 是一个功能强大的构建工具,可以用于管理和打包各种资源,包括样式文件。
- 安装依赖:首先,我们需要在项目中安装Webpack和相应的样式加载器,例如
style-loader
和css-loader
。 - 配置样式加载器:在
Webpack
配置文件中,我们可以配置不同类型的样式加载器,例如处理CSS、Sass、Less等。我们还可以使用MiniCssExtractPlugin
插件将样式提取为单独的CSS文件。
// webpack.config.js const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { // ... 其他配置项 ... module: { rules: [ { test: /\.css$/, // 匹配以 .css 结尾的文件 use: [ MiniCssExtractPlugin.loader, // 使用 MiniCssExtractPlugin 将样式提取为单独的文件 'css-loader', // 解析 CSS 'postcss-loader', // 可选,用于处理 CSS 前缀等 ] }, // 添加其他样式格式的规则(如 Sass、Less 等) ] }, plugins: [ new MiniCssExtractPlugin({ filename: 'styles.css' // 输出的提取后的样式文件名为 styles.css }) ] };
- 在应用中引入样式:在我们的应用代码中,我们可以直接引入样式文件,Webpack 会处理并将其合并到输出文件中。
// app.js import './styles.css';
Vite 管理样式:
Vite 是一个基于ESM的构建工具,它具有快速的冷启动和实时更新能力,适用于开发环境。
- 安装依赖:我们需要在项目中安装 Vite。
- 配置样式:Vite 使用默认的样式预处理器,例如 CSS、Sass、Less,无需额外的配置。
- 在应用中引入样式:在我们的应用代码中,我们可以直接引入样式文件,Vite 会自动处理。
// app.js import './styles.css';
Vite 会在开发过程中使用 HMR(热模块替换)来实现实时更新。
可以看潜聊vite
在使用HTTP/2
的情况下,连接不再那么必要,因为它可以对请求进行流水线和多路复用。在某些情况下,如果我们有较小且经常更改的CSS资源,分开的文件可能会有益。然而,大多数网站可能会从发送一个立即由浏览器缓存的单个文件中受益。
当启用GZIP
时,缩小可能不会带来显着的好处。尽管如此,实际上并没有什么不利之处。
8.使用现代布局技术
多年来,使用CSS浮动来布局页面是必要的。这种技术是一种“黑科技”。它需要大量的代码和边距/填充微调来确保布局正常工作。即使如此,在较小的屏幕尺寸下,浮动也会出现问题,除非添加了媒体查询。
现代的替代方案有:
- CSS Flexbox 用于一维布局,可以根据每个块的宽度换行到下一行。Flexbox非常适用于菜单、图像画廊、卡片等。
- CSS Grid 用于具有显式行和列的二维布局。Grid非常适用于页面布局。
这两个选项都更容易开发,使用更少的代码,可以适应任何屏幕尺寸,并且比浮动渲染得更快,因为浏览器可以本地确定最佳布局。
这里就不得不墙裂推荐,阮一峰大佬写的关于Flex
/Gird
的教程了.
9. 为CSS瘦身
最可靠且速度最快的代码就是我们永远不需要编写的代码!样式表越小,下载和解析速度就越快。
所有开发人员都以良好的意图开始,但随着功能数量的增加,CSS可能会变得越来越庞大。保留旧的、不必要的代码比删除它并冒着破坏某些东西的风险要容易。以下是一些建议供考虑:
- 谨慎使用大型CSS框架。
- 将CSS组织成具有明确职责的较小文件(部分文件)。
- 考虑使用诸如BEM之类的命名方法,以帮助开发独立的组件。
- 避免深层嵌套的Sass等预处理器声明。扩展后的代码可能会意外地变得很大。
- 避免使用
!important
来覆盖样式。 - 避免在HTML中使用内联样式。
由于现在是前端框架的天下,所以在进行CSS瘦身
时,离不开构建工具的处理.
下面我们就针对Webpack4/Webpack5/Vite
如何进行CSS瘦身
做一次简单介绍
Webpack 4
Webpack 4
通常使用purgecss-webpack-plugin
插件来删除无用的CSS。该插件会根据代码中实际使用的类名,从构建后的CSS中移除未使用的样式。
安装插件:
npm install purgecss-webpack-plugin --save-dev
在Webpack配置中使用插件:
const PurgeCSSPlugin = require('purgecss-webpack-plugin'); module.exports = { // ... plugins: [ new PurgeCSSPlugin({ paths: glob.sync(['src/**/*.js'], { nodir: true }), }), // ... ], };
这将根据项目中的JavaScript文件中实际使用的类名,从构建后的CSS中删除未使用的样式。
purgecss-webpack-plugin
需要与mini-css-extract-plugin
配合使用,才会达到最佳效果, 具体配置可以参考purgecss-webpack-plugin用法
Webpack 5
在Webpack 5
中,无用CSS的删除通常是内置的特性,不需要额外的插件。Webpack 5会自动分析代码并从构建后的CSS中删除未使用的样式。
这个特性的底层原理涉及Webpack的代码分析功能和Tree Shaking
技术:
- 代码分析功能:Webpack 5能够分析整个项目的代码结构,包括入口文件、依赖关系和引用关系。它可以检测哪些CSS类名在项目的JavaScript文件中被实际使用,以及哪些未被使用。
- Tree Shaking:这是一种用于剔除不使用的代码的优化技术,它会在打包过程中移除不会被执行的代码。在CSS中,这意味着Webpack 5会识别哪些CSS样式类在JavaScript代码中没有被引用,然后将这些未使用的样式从构建后的CSS中删除。
底层原理的实现涉及Webpack的构建流程和代码解析算法。Webpack会从入口文件开始,递归地分析所有依赖的JavaScript文件,同时识别哪些CSS类名在实际代码中被使用。一旦确定了未使用的CSS类名,Webpack就会在构建最终的CSS文件时将其删除,从而减少输出的文件大小。
Vite
Vite是一个基于ES模块
的前端构建工具,它在开发模式下通过ES模块的引用关系来实现无用CSS的删除。
在Vite中,无用CSS的删除是默认的特性,不需要额外的配置。Vite会在开发模式下自动删除未使用的CSS。
10. 坚持使用层叠特性
CSS-in-JS
的兴起使开发人员能够避免使用CSS全局命名空间。通常,在构建时会创建随机生成的类名,从而使组件之间不可能发生冲突。
如果CSS-in-JS改善了我们的工作流程,那么继续使用它是可以的。然而,了解CSS级联的好处也是值得的,而不是在每个项目中都与之对抗。例如,我们可以设置默认字体、颜色、大小、表格和表单字段,这些样式会统一应用于单个位置中的每个元素。很少有必要在每个组件中声明每个样式。
11. 简化选择器
即使是最复杂的CSS选择器也只需要几毫秒来解析,但减少复杂性会减小文件大小并帮助浏览器解析。
假设有如下的页面结构,现在我们想要选择下载PDF的对应的元素.
<body> <main class="main"> <section class="first"> <h2>前端</h2> <h2>柒八九</h2> <!-- 符合 nth-of-type(odd) 条件 --> <p> <span>第一行内容</span> <a href="document.pdf">下载 PDF</a> <!-- 符合 [href$=".pdf"] 条件 --> </p> <p> <span>其他内容信息</span> <a href="image.jpg">下载 Image</a> </p> </section> </main> </body>
如果有同组的小可爱给你写下面的选择器,就问你看到这个代码迷糊不迷糊.
body > main.main > section.first h2:nth-of-type(odd) + p::first-line > a[href$=".pdf"]
本着人道主义的关怀,我还是给你浅浅的解释一下每段代码的含义哇.
body
: 选择文档中的<body>
元素。>
: 选择直接子元素的关系符。main.main
: 选择类名为main
的<main>
元素。>
: 再次使用直接子元素的关系符。section.first
: 选择类名为first
的<section>
元素。h2:nth-of-type(odd)
: 选择是奇数序号的<h2>
元素。这里假设<h2>
元素是<section>
的子元素,并且是奇数序号的。+
: 选择紧接在前一个元素后的元素。p::first-line
: 选择<p>
元素的第一行。a[href$=".pdf"]
: 选择链接的<a>
元素,其中链接的href
属性以.pdf
结尾。
同样,要谨慎使用像Sass这样的预处理器中的深层嵌套,因为这可能会无意中创建复杂的选择器。