一、 环境搭建
本篇演示使用vite 搭建一个简单的项目来看演示效果。搭建步骤如下:
1、 新建一个项目vite-scss
2、 初始化项目: pnpm init
,这时候会生成packages.json
3、 安装vite: pnpm i vite -D
4、 在packages.json中添加打包命令
js
"scripts": {
"dev": "vite",
"build": "vite build"
},
5、 安装sass: pnpm i sass -D
6、 根目录下新建index.html作为vite 的入口文件
7、 根目录下面创建src 目录
8、 src 下面创建css 目录和js目录
9、 css 目录下创建index.scss
10、 js 目录下创建index.js
11、 index.js中引入index.csss
12 index.html中引入index.js , 注意scrpit标签上必须添加type="module"
搭建完成之后目录结构如下:

13、 运行项目:pnpm run dev
14、 预览效果: 打开浏览器输入http://localhost:5173
二、scss 嵌套语法
在早期的原生csss是不支持嵌套的写法的,所以我们为了css 样式尽量的不出现覆盖,我们会一直在前面重复写父级的类名来规避。会非常麻烦,这个时候就scss就很好的解决了这个问题。scss提供了嵌套写法,使得我们不用重复写父级的类名,且结构更加清晰易读。现在我们用scss来写一个简单的导航:
html 结构如下
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vite+scss</title>
</head>
<body>
<nav>
<a href="#">首页</a>
<a href="#">列表</a>
<a href="#">个人中心</a>
</nav>
<script src="./src/js/index.js" type="module"></script>
</body>
</html>
index.scss
css
nav {
display: flex;
justify-content: space-around;
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.3);
a {
color: #333;
text-decoration: none;
padding: 6px 16px;
}
}
浏览器f12可以在浏览器调试工具中看到编译后css:
可以看到我们编写scss 被编译成了普通的css
三、scss 中变量的使用
在早期的css 中同样不支持变量的写法,这样使得我们在实现某些需求的时候就非常麻烦,比如说现在有一个需求,要开发一个产品,这个产品有不同的品牌,不同品牌之间除了颜色不同外其他基本相同,这个时候如果没有scss 我们可能就会想着写两套代码,来实现这个需求,这样就需要维护两套代码,造成了很大的维护成本,产品更新的时候需要两套代码同时更新。而有了scss 变量 就可以很好的解决这个问题。还是以之前的导航为例:
html 结构中增加选中导航的类名:

在src/css下面增加品牌配置变量的scss文件,brand.scss
scss
// 品牌主风格颜色变量
$color: blue;
$active-bg: yellow;
根目录新增vite.config.js配置文件,内容如下:
js
// vite.config.js
import { defineConfig } from "vite";
import path from "path";
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `
@use "@/css/brand.scss" as *;
`, // 配置全局scss
},
},
},
resolve: {
alias: {
"@": path.resolve(__dirname, "src"), // 配置别名
},
},
});
修改index.scss
scss
nav {
display: flex;
justify-content: space-around;
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.3);
a {
color: $color; // 使用导航文字颜色变量
text-decoration: none;
padding: 6px 16px;
&.active{ // 选中的类样式
background: $active-bg; // 使用选中的颜色变量
color: #fff;
}
}
}
主要修改以下内容:
这样要把不同品牌的代码发布到不同平台就非常简单了,只需要修改brand.scss中的变量,然后重新打包发布即可。甚至你可以将不同品牌的变量写成多个文件,通过命令的mode参数引用不同的文件。
上面的scss代码编译后同样会生成普通的css,将变量替换为我们定义时候的值:

四、混合指令
scss 的混合指令可以减少样式中相同部分样式的书写,来直接看例子
1. 不带参数的混合指令
html 结构:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vite+scss</title>
</head>
<body>
<button class="primary">按钮</button>
<button class="sucecss">按钮</button>
<script src="./src/js/index.js" type="module"></script>
</body>
</html>
index.scss
scss
@mixin button-style{ // 定义按钮的混合指令
padding: 8px 20px;
font-size: 16px;
border-radius: 5px;
color: #fff;
border: none;
outline: none
}
.primary{
@include button-style; // 引用按钮的混合指令
background: #409EFF;
}
.sucecss {
@include button-style; // 引用按钮的混合指令
background: #67C23A;
}
运行效果:

编译成css 后的样子:

可以看到混合指令在编译后,会把混合指令中的样式复制到引用混合指令的地方。
2. 带参数的混合指令
混合指令可以像js中函数一样可以传递参数,通过传递参数可以增强代码的复用性和可维护性。将上述按钮的scss实现代码优化一下。
scss
@mixin button-style($bg-color){ // 定义按钮的混合指令
padding: 8px 20px;
font-size: 16px;
border-radius: 5px;
color: #fff;
border: none;
outline: none;
background: $bg-color;
}
.primary{
@include button-style(#409EFF); // 引用按钮的混合指令
}
.sucecss {
@include button-style(#67C23A); // 引用按钮的混合指令
}
主要修改部分:

查看编译结果:
可以看到编译结果和之前是一样的。
3. 带有默认参数值的混合指令
和es6中的函数一样,混合指令的参数也可以定义默认值。具体使用方式如下:
index.scss
scss
@mixin button-style($bg-color: #409EFF){ // 定义按钮的混合指令
padding: 8px 20px;
font-size: 16px;
border-radius: 5px;
color: #fff;
border: none;
outline: none;
background: $bg-color;
}
.primary{
@include button-style; // 引用按钮的混合指令
}
.sucecss {
@include button-style(#67C23A); // 引用按钮的混合指令
}
主要修改内容:

可以看到我们将.primary的背景颜色值定义为了默认颜色,调用时不用传参就能达到我们想要的效果。

五、扩展/继承指令
扩展/继承指令 和混合指令功能有点类似,但也有很大差别。
- 相同点: 都是为了实现一些样式属性的复用
- 不同点: 混合指令可以传参数,扩展/继承指令不能传参数,混合指令编译后是将定义混合指令里的内容复制到引用混合的地方,而扩展/继承指令则是将这些相同的部分抽离成分组选择器。
来看扩展/继承指令 的使用:
scss
.btn { // 定义按钮的混合指令
padding: 8px 20px;
font-size: 16px;
border-radius: 5px;
color: #fff;
border: none;
outline: none;
}
.primary{
@extend .btn; // 引用按钮的混合指令
background: #409EFF;
}
.sucecss {
@extend .btn; // 引用按钮的混合指令
background: #67C23A;
}
可以看到扩展/继承指令使用@extend 来实现。编译结果如下:
可以看到,@extend 比混合指令的编译出来的代码更简洁。
六、站位符%
细心的你可能会发现上面我们实现的继承的代码中的.btn这个类名编译后我们并不需要它,但是编译后它仍然存在,这不是我们想要的。这个时候就可以使用站位符来解决这个问题。
修改index.scss
scss
%btn { // 定义按钮的混合指令
padding: 8px 20px;
font-size: 16px;
border-radius: 5px;
color: #fff;
border: none;
outline: none;
}
.primary{
@extend %btn; // 引用按钮的混合指令
background: #409EFF;
}
.sucecss {
@extend %btn; // 引用按钮的混合指令
background: #67C23A;
}
可以看到占位符以%开头,后面跟选择器名称,注意不要点
看看编译结果:

可以看到btn 在编译后就不存在了。
总结一下混合指令,扩展/继承指令,占位符的优缺点:
- 三者都可以在看开发阶段节省代码
- 混合指令,可以传参数,可以根据参数来决定渲染,开发阶段看上去更简单灵活,但是编译后代码重复的相对较多。
- 继承普通类如果直接继承一个类,而这个类在html结构中又没有使用到,编译后则会多出一些无用的类
- 继承占位符,如果继承的类在html结构中没有用到,则使用占位符代替,使得代码编译后更简洁
综上所述:在需要传参时优先使用混合指令,如果一个被继承的类在html结构中有使用到,则直接使用继承普通类名称,如果被继承的类在html结构中没有被使用到则使用占位符
七、父选择器 &
其实在之前的导航案例中我们就用到了 &,接下来就来介绍下 & 的用法
scss
nav {
&.list{
color: #333;
}
}
nav {
& .list {
color: #333;
}
}
nav {
.list & {
color: #333;
}
}
编译结果:
可以看到 & 有三种用法,所以写的时候要知道自己需要的是哪种,它们编译后的结果是不一样的。第一种方式是最常用的。后面两种几乎不用。
七、总结
本篇介绍了scss 最常用的5个功能,运用好它们让我们在项目开发中写出的代码更简洁,更高效,在选择混合选择器,继承/扩展指令,占位符时要注意哪个场景适合它们。
今天的分享就到这里了,感谢收看