Sass
第一章:走进 Sass
一、Sass 简介
1. CSS 预处理器的概念
CSS 预处理器用一种专门的编程语言,进行 Web 页面样式设计,然后再编译成正常的 CSS 文件,以供项目使用。CSS 预处理器为 CSS 增加一些编程的特性,无需考虑浏览器的兼容性问题。例如说:Sass(SCSS)、LESS、Stylus、Turbine、Switch CSS、CSS Cacheer、DT CSS 等,均属于 CSS 预处理器。其中比较优秀的有 Sass、LESS、Stylus。
2. Sass 是什么
Sass 是世界上最成熟、最稳定、最强大的专业级 CSS 扩展语言!
简单来说就是 CSS 预处理器。
文档地址
Sass 的官方网站:sass-lang.com
中文文档
- 中文文档网站(由社区维护):www.sass.hk
- Nodejs.cn 旗下:Sass 中文网
- 其他中文文档:Sass Guidelines
Sass 和 SCSS 区别
Sass 从第三代开始,加入了缩进式风格,并且完全向下兼容普通的 CSS 代码,这一代的 Sass 也被称为 SCSS(Sassy CSS)。
总结:目前 Sass 新版支持两种写法。Sass 是旧版,语法采用缩进。SCSS 是新版,语法采用 {}。目前官方推荐语法使用 SCSS。
3. Sass 编译器实现版本
- Dart Sass (包名 sass)
- 目前的官方实现,也是唯一被积极维护和推荐的版本。
- 由 Sass 官方团队用 Dart 语言编写,然后可以编译成纯 JavaScript 在 Node.js 环境中运行。
- 优点是安装简单、功能最新、跨平台兼容性好。
- 通过安装 sass 这个 npm 包 (也就是 Dart Sass) 来进行编译。
- GitHub 仓库:https://github.com/sass/dart-sass
- LibSass (包名
node-sass) :LibSass 版本说明- 已经停止维护,不推荐使用。
- 用 C/C++ 编写的高性能编译库。
- 曾经因为速度快而流行,但由于安装困难、跟不上 Sass 语言新特性等问题已被废弃。
- 2025 年 10 月结束了生命周期。
- GitHub 仓库:https://github.com/sass/libsass
Ruby Sass:Ruby Sass 版本说明
2019 年 3 月 26 日终止生命周期。
……
二、环境变量配置安装
方法一:sass 包
npm sass 介绍:sass
npm install -g sass
# 推荐
npm install --save-dev sass不推荐这种使用方式学习 sass,这种使用方式都是在脚手架中。推荐使用 Live Sass Compiler 插件。
# 采用单个 Sass 文件 input.scss,并将该文件编译为 output.css
sass input.scss output.css
# 每次保存了 input.scss 会自动重新编译
sass --watch input.scss output.css
# Sass 会监视 app/sass 文件夹中的所有文件是否发生更改,并将 CSS 编译到 public/stylesheets 文件夹
sass --watch app/sass:public/stylesheets方法二:VScode 集成
1)Live Sass Compiler
2)点击管理(设置的小符号)3)点击扩展设置
4)点击【在 settings.json 中编辑】
配置选项参考:VScode Live sass - compiler/docs/settings.md
{
"liveSassCompile.settings.formats": [
{
/*
expanded - 展开格式
compressed - 压缩格式
*/
"format": "expanded", // 指定输出的css格式
"extensionName": ".css", // 添加到输出文件的扩展名后缀 (必须以 .css 结尾)
/*
~ 代表当前正在被编译的 Sass 文件所在的目录
null 表示当前目录
*/
"savePath": "~/../css"
}
],
// 排除目录
"liveSassCompile.settings.excludeList": [
"/**/node_modules/**",
"/.vscode/**",
"/.history/**"
],
// 是否生成对应的map
"liveSassCompile.settings.generateMap": false,
// 是否添加兼容前缀, 例如:-webkit- -moz- ... 等
"liveSassCompile.settings.autoprefix": [
"> 1%",
"last 2 versions"
],
"explorer.confirmDelete": false // 在文件资源管理器中删除文件时,不再弹出确认提示框
}5)复制上面代码到第四步打开的 settings.json 文件中。
6)点击底部状态栏的 Watch Sass 来开启此插件。
备注:相关的 VSCode 插件还有 scss-to-css。
第二章:基础语法
一、注释
语法
单行注释:编译后,单行注释不在 CSS 中
// 单行注释多行注释
/*
多行注释
*/文档注释
/// 文档注释保留注释
如果是压缩输出模式,那么注释也会被去掉,这个时候可以在多行注释的第一个字符书写一个 ! ,此时即便是在压缩模式,这条注释也会被保留,通常用于添加版权信息。
/*!
该 CSS 作者 XXX
创建于 xxxx年xx月xx日
*/
.test{
width: 300px;
}二、选择器的书写
1. 选择器嵌套
1)后代选择器 / 基础选择器
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}SCSS 选择器嵌套它是一层层的父元素里面套着子元素,这样有助于后期代码的维护。
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}2)并集选择器 / 列表选择器
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}.alert ul, .alert p, .warning ul, .warning p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}3)结构选择器 / 选择器组合器
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ span {
opacity: 0.8;
}
}ul > li {
list-style-type: none;
}
h2 + p {
border-top: 1px solid gray;
}
p ~ span {
opacity: 0.8;
}2. 父选择器 &
在嵌套 CSS 规则时,有时也需要直接使用嵌套外层的父选择器,例如,当给某个元素设定 hover 样式时,或者当 body 元素有某个 classname 时,可以用 & 代表嵌套规则外层的父选择器。
总结:& 将被替换成嵌套外层的父选择器,如果含有多层嵌套,最外层的父选择器会一层一层向下传递。
例如有这么一段样式:
.container {width: 1200px;margin: 0 auto}
.container a {color: #333;}
.container a:hover {text-decoration: underline;color: #f00;}
.container .top {border: 1px #f2f2f2 solid;}
.container .top-left {float: left; width: 200px;}用 SCSS 编写:
带伪类选择器的元素我们可以把它放到它的父类下面,但不能直接放,我们需要在伪类的前面放 & 。
以下面代码为例,.top 下的 &-left 代表的 .top-left,这是 & 代表 .top 。
.container {
width: 1200px;
margin: 0 auto;
a {
color: #333;
&:hover {
text-decoration: underline;
color: #f00;
}
.top {
border: 1px #f2f2f2 solid;
&-left {
float:left;
width: 200px;
}
}
}
}3. 属性选择器
有些 CSS 属性遵循相同的命名空间(namespace),比如 font-family,font-size,font-weight 都以 font 作为属性的命名空间。为了便于管理这样的属性,同时也为了避免了重复输入,Sass 允许将属性嵌套在命名空间中。
CSS 写法:
.container a {
color: #333;
font-size: 14px;
font-family: sans-serif;
font-weight: bold;
}SCSS 写法:
.container {
a {
color: #333;
font: {
size: 14px;
family: sans-serif;
weight: bold;
}
}
}命名空间也可以包含自己的属性值,例如:
.funky {
font: 20px/24px {
family: fantasy;
weight: bold;
}
}编译为:
.funky {
font: 20px/24px;
font-family: fantasy;
font-weight: bold;
}注意:font: 后面要加一个空格。
4. 占位符选择器 %foo 必须通过 @extend
有时,需要定义一套样式并不是给某个元素用,而是只通过 @extend 指令使用。尤其是在制作 Sass 样式库的时候,希望 Sass 能够忽略用不到的样式。定义的样式在不使用的情况下不会编译出来。
例如有这样一段编译前样式:
.buttom%base {
display: inline-block;
margin-bottom: 0;
border: 1px solid red;
}
.btn-default {
@extend %base;
color: #faa;
width: 60px;
}
.btn-success {
@extend %base;
color: #faa;
width: 60px;
}编译后
.buttom.btn-default, .buttom.btn-success {
display: inline-block;
margin-bottom: 0;
border: 1px solid red;
}
.btn-default {
color: #faa;
width: 60px;
}
.btn-success {
color: #faa;
width: 60px;
}三、插值语句 #{}
类似 ES6 的模板字符串。
p {
font: 16px/30px Arial,Helvetia,sans-serif;
}如果需要使用变量,同时又要确保不做除法运算,而是完整的编译到 CSS 文件中,只需要用 #{} 插值语句将变量包裹。
$font-size: 16px;
$height: 30px;
p {
font: #{$font-size}/#{$height};
}四、流程控制指令
其他指令见第四章。
1. @if 和 @else
.container{
// 第一种
@if(/* 条件 */){
// ...
}
// 第二种
@if(/* 条件 */){
// ...
}@else{
// ...
}
// 第三种
@if(/* 条件 */){
// ...
}@else if(/* 条件 */){
// ...
}@else{
// ...
}
}例如:
%triangle {
width: 0px;
height: 0px;
display: inline-block;
}
@mixin triangle($direction: top, $size: 30px, $border-color: black) {
border-width: $size;
border-#{$direction}-width: 0;
@if ($direction==top) {
border-color: transparent transparent $border-color transparent;
border-style: dashed dashed solid dashed;
} @else if ($direction==right) {
border-color: transparent transparent transparent $border-color;
border-style: dashed dashed dashed solid;
} @else if ($direction==bottom) {
border-color: $border-color transparent transparent transparent;
border-style: solid dashed dashed dashed;
} @else if ($direction==left) {
border-color: transparent $border-color transparent transparent;
border-style: dashed solid dashed dashed;
}
}
.p0 {
@extend %triangle; // 继承
@include triangle(right,30px,#aff); // 混入
}
.p1 {
@extend %triangle;
@include triangle(bottom,30px,#afa);
}
.p2 {
@extend %triangle;
@include triangle(left,30px,#faa);
}
.p3 {
@extend %triangle;
@include triangle(right,30px,#aaf);
}使用
<p class="p0"></p>
<p class="p1"></p>
<p class="p2"></p>
<p class="p3"></p>2. @for
1)语法
@for 指令可以在限制的范围内重复输出格式,每次按照要求(变量的值)对输出结果做出变动。这个指令包含两种格式:
@for <$var> from <start> to <end> { ... }@for <$var> from <start> through <end> { ... }
区别在于 through 与 to 的含义:
- 当使用 through 时,遍历范围
[start, end]。 - 而是用 to 时,遍历范围
[start, end)。 <start>和<end>必须是整数值。
2)例子
例 1
@for $i from 1 to 4 { // 生成 .p1 到 .p3
.p#{$i} {
width: 10 * $i;
height: 30px;
background-color: red;
}
}
@for $i from 1 through 3 { // 生成 .p1 到 .p3
.p#{$i} {
width: 10 * $i;
height: 30px;
background-color: red;
}
}例 2
@keyframes loading {
0% {
opacity: 0.3;
transform: translateY(0px);
}
50% {
opacity: 1;
transform: translateY(-20px);
background: green;
}
100% {
opacity: 0.3;
transform: translateY(0px);
}
}
#loading {
position: fixed;
top: 200px;
left: 46%;
}
#loading span {
position: absolute;
width: 20px;
height: 20px;
background: #3498db;
opacity: 0.5;
border-radius: 50%;
animation: loading 1s infinite ease-in-out;
}
@for $i from 1 to 6 {
#loading span:nth-child(#{$i}) {
left: 20 * ($i - 1) + px;
// animation-delay: 20 * ($i - 1) / 100 + s;
animation-delay: unquote(
$string: "0." +
(
$i - 1,
) *
2 +
s
);
}
}使用
<div id="loading">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>3. @each
@each 指令的格式是 $var in <list>,$var 可以是任何变量名,比如 $length 或者 $name,而 <list> 是一连串的值,也就是值列表。
例如做如下效果
普通 CSS 的写法
p {
width: 10px;
height: 10px;
display: inline-block;
margin: 10px;
z-index: 5;
}
.p0 {
background-color: red;
}
.p1 {
background-color: green;
}
.p2 {
background-color: blue;
}
.p3 {
background-color: turquoise;
}
.p4 {
background-color: darkmagenta;
}Sass 的写法:
$var: 10;
p {
width: 10px;
height: 10px;
display: inline-block;
margin: 10px;
z-index: $var - 5;
}
$color-list: red green blue turquoise darkmagenta;
@each $color in $color-list {
$index: index($color-list, $color);
.p#{$index - 1} {
background-color: $color;
}
}4. @while
1)语法
@while 指令重复输出格式直到表达式返回结果为 false。这样可以实现比 @for 更复杂的循环。格式:@while <expression> { ... }
2)例子
用 scss 实现 bootstrap 中 css 的这么一段代码。
http://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.css
.col-sm-12 {
width: 100%;
}
.col-sm-11 {
width: 91.66666667%;
}
.col-sm-10 {
width: 83.33333333%;
}
.col-sm-9 {
width: 75%;
}
.col-sm-8 {
width: 66.66666667%;
}
.col-sm-7 {
width: 58.33333333%;
}
.col-sm-6 {
width: 50%;
}
.col-sm-5 {
width: 41.66666667%;
}
.col-sm-4 {
width: 33.33333333%;
}
.col-sm-3 {
width: 25%;
}
.col-sm-2 {
width: 16.66666667%;
}
.col-sm-1 {
width: 8.33333333%;
}用 @while 实现。
@use "sass:string";
$column: 12;
@while $column>0 {
.col-sm-#{$column} {
width: $column / 12 * 100%;
width: $column / 12 * 100#{"%"};
// width: $column / 12 * 100 + %; 会报错
// width: unquote($string: $column / 12 * 100 + "%"); 过时
width: string.unquote($string: calc($column / 12) * 100 + "%");
}
$column: $column - 1;
}5. 元运算符
if(expression, value1, value2)例子:
p {
color: if(1+1==2, green, yellow);
}
div {
color: if(1+1==3, green, yellow);
}p {
color: green;
}
div {
color: yellow;
}第三章:Sass Script
一、变量
1. 声明
- 变量以美元符号 ($) 开头,后面跟变量名;
- 变量名是不以数字开头的,可包含字母、数字、下划线、横线(连接符);
- 变量值写法同 css,即变量名和值之间用冒号 (😃 分隔;
- 变量一定要先定义后使用;
$color: #faa;
$border-color: #afa;
$border-width: 1px;
.container {
color: $color;
border-color: $border-color;
}注意
通过连接符与下划线定义的同名变量为同一变量,建议使用连接符。
$font-size: 14px;
$font_size: 16px;
.container{font-size: $font-size;} // 16px2. 作用域
1)局部变量
定义:在选择器内容定义的变量,只能在选择器范围内使用。
.container {
$font-size:14px;
font-size: $font-size;
}2)全局变量
定义:定义后能全局使用的变量。
第一种:在选择器外面的最前面定义的变量
$font-size: 16px;
.container {
font-size: $font-size;
}
.footer {
font-size: $font-size;
}第二种:使用 !global 标志定义全局变量
.container {
$font-size: 16px !global;
font-size: $font-size;
}
.footer {
font-size: $font-size;
}3. 数据类型
SCSS 支持 7 种主要的数据类型。
- 数字:
16, 10px, 30% - 字符串:有引号字符串与无引号字符串,
"foo", 'bar', baz - 颜色:
blue, #04a3f9, rgba(255,0,0,0.5) - 布尔型:
true, false - 空值:
null - 数组(list):用空格或逗号做分隔符,
1.5em 1em 0 2em, Helvetica, Arial, sans-serif - 字典(maps):相当于 JavaScript 的 object,
(key1: value1, key2: value2)
$layer-index: 10; // 数字不带单位
$border-width: 3px; // 数字带单位
$font-base-family: "Open Sans", 'Helvetica', Sans-Serif; // 字符串
$top-bg-color: rbga(255, 147, 29, 0.6); // 颜色
$blank-mode: true; //布尔
$var: null; // 值 null 是其类型的唯一通道。它表示缺少值,通常由函数返回,以指示缺少结果。
// 数组
$color-map: 1px 2px, 5px 6px; // 包含 1px 2px 与 5px 6px 两个数组的数组
$fonts: ( // map
color1: #fa0000,
color2: #fbe200,
color3: #95d7eb,
serif: "Helvetica Neue",
monospace: "Consolas",
);使用
.container {
$font-size: 16px !global;
font-size: $font-size;
@if $blank-mode {
background-color: map-get($color-map, color1);
} @else {
background-color: map-get($color-map, color2);
}
content: type-of($var);
content: length($var);
color: map-get($color-map, color3);
}
.footer {
font-size: $font-size;
}
// 如果列表中包含空值,则生成的 CSS 中将忽略该空值。
.wrap {
font: 18px bold map-get($fonts, "sans");
}值列表:可以用空格或逗号分隔,并且可以用方括号括起来或根本不加括号。例如 1.5em 1em 0 2em、Helvetica, Arial, sans-serif 或 [col1-start]。
4. 默认值
$color: #333;
// 如果 $color 之前没定义就使用如下的默认值
$color: #666 !default;
.container {
border-color: $color;
}二、运算符
1. 等号操作符
所有数据类型均支持相等运算 == 或 !=,此外,每种数据类型也有其各自支持的运算方式。
| 符号 | 说明 |
|---|---|
| == | 等于 |
| != | 不等于 |
比较规则
- 如果数字具有相同的值和相同的单位,或者它们的单位相互转换后的值相等,则数字相等。
- ……
2. 关系或比较运算符
| 符号 | 说明 |
|---|---|
| < (lt) | 小于 |
| > (gt) | 大于 |
| <= (lte) | 小于等于 |
| >= (gte) | 大于等于 |
例子
// 单位相同或无单位
@debug 100 > 50; // true
@debug 10px < 17px; // true
// 无单位的会转为参与比较的单位
@debug 100 > 50px; // true
@debug 10px < 17; // true
// 单位不兼容的会报错3. 逻辑运算符
| 符号 | 说明 |
|---|---|
| and | 逻辑与 |
| or | 逻辑或 |
| not | 逻辑非 |
例 1:
@debug not true; // false
@debug not false; // true
@debug true and true; // true
@debug true and false; // false
@debug true or false; // true
@debug false or false; // false4. 数字操作符
| 符号 | 说明 |
|---|---|
| + | 加 |
| - | 减 |
| * | 乘 |
| % | 取模 |
注意:Sass 中的除法是通过
math.div()函数完成的。
注意
数字类型包括:纯数字、百分号、css 部分单位(px、pt、in...)
% 与 单位不能一起运算
纯数字与百分号或单位运算时会自动转换成相应的百分号与单位值
以下三种情况将被视为除法运算符号
- 如果值或值的一部分,是变量或者函数的返回值
- 如果值被圆括号包裹
- 如果值是算数表达式的一部分
例
/* ========== / 运算 ============ */
$width: 100px;
div{
font: 16px/30px Arial,Helvetica, sans-serif; //不运算
width: (10/5); // 使用了小括号
width: $width / 10; //使用变量与括号
width: round(50) /2; //使用了函数
width: 50px / 10 + 50px; // 使用了 + 表达式
}如果需要使用变量,同时又要确保/不做除法运算而是完整的编译到 CSS 文件中,只需要用 #{} 插值语句将变量包裹。
5. 字符串运算符
<expression> + <expression>返回包含两个表达式值的字符串。scss@debug "Helvetica" + " Neue"; // "Helvetica Neue" @debug "Helvetica" + Neue; // "HelveticaNeue" @debug Helvetica + " Neue"; // Helvetica Neue @debug Helvetica + Neue; // HelveticaNeue注意:如果有引用字符串(位于 + 左侧)连接无引号字符串,运算结果是有引号的;无引号字符串(位于 + 左侧)连接有引号字符串,运算结果则没有引号。
<expression> - <expression>返回一个不带引号的字符串,其中包含两个表达式的值,并用-分隔。这是一个旧版运算符,通常应使用插值法来代替。scss@debug sans- + serif; // sans-serif @debug sans- + "serif" // sans-serif @debug sans - serif; // sans-serif
6. 布尔运算符
@debug not true; // false
@debug not false; // true
@debug true and true; // true
@debug true and false; // false
@debug true or false; // true
@debug false or false; // false第四章:@-Rules 与指令
一、导入样式
1. @use
@use 加载的样式表称为“模块”。
// 若文件后缀为 scss、sass、css 时, 可省略
@use 'src/corners.scss'; // 默认命名空间为文件名 corners
@use "src/corners.scss" as c; // 命名空间为 c
@use "src/corners.scss" as *; // 无命名空间, 直接就能用里面的内容2. @forward
// 用法与 @use 大致一致, 就是不能在本文件中使用, 需要在其他文件通过 @use 引入本文件才行
@forward 'src/corners.scss';
@forward "src/list" as list-*;3. @import
从 Dart Sass 1.80.0 开始,
@import规则是已弃用,并将在 Dart Sass 3.0.0 中从语言中删除。
1)基本使用
Sass 扩展了 @import 的功能,允许其导入 Scss 或 Sass 文件。被导入的文件将合并编译到同一个 CSS 文件中,另外,被导入的文件中所包含的变量或混合指令 (mixin) 都可以再导入的文件中使用。
例子
public.scss
$font-base-color: #333;在 index.scss 里面使用
@import "public";
$color:#666;
.container {
border-color: $color;
color:$font-base-color;
}注意:跟普通 css 里面 @import 的区别。
如以下几种方式,都将作为普通的 css 语句,不会导入任何 SCSS 文件
- 文件扩展名是 .CSS;
- 文件名以 http:// 开头;
- 文件名是 url();
- @import 包含 media queries。
@import "public.css";
@import url(public);
@import "http://xxx.com/xxx";
@import 'landscape' screen and (orientation:landscape);2)局部文件 (Partials)
SCSS 文件夹下的 SCSS 文件都会被监听且自动编译,取消编译的方法在文件夹名称前加下划线 (_) ,否则文件会被自动编译。
@import "_public.scss" // 导入的时候可以不加下划线和文件后缀 例:@import "public"注意:不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略。
3)嵌套 @import
把局部的 SCSS 文件嵌套在选择器里面。
假设 example.scss 文件包含以下样式:
.example {
color: red;
}然后导入到 #main 样式内
#main {
@import "example";
}将会被编译为
#main .example {
color: red;
}注意:不可以在混合指令 (mixin) 或控制指令 (control directives) 中嵌套 @import。
二、混合指令
混合指令 (Mixin Directives) 用于定义可重复使用的样式。混合指令可以包含所有的 CSS 规则、绝大部分 SCSS 规则,甚至通过参数功能引入变量,输出多样化的样式。
1. 定义混合指令 @mixin
1)语法
混合指令的用法是在 @mixin 后添加名称与样式。
@mixin mixin-name() {
/* CSS 声明 */
}2)使用例子
标准形式
// 定义页面一个区块基本的样式
@mixin block () {
width: 96%;
margin-left: 2%;
border-radius: 8px;
border: 1px #f6f6f6 solid;
}
// 使用混入
.container {
.block {
@include block;
}
}参数形式
// 定义 flex 布局元素纵轴的排列方式
@mixin flex-align($aitem) {
--webkit-box-align: $aitem;
--webkit-align-items: $aitem;
--ms-flex-align: $aitem;
align-items: $aitem;
}
// 使用
.container {
@include flex-align(center)
}可选参数 / 默认值
@mixin replace-text($image, $x: 50%, $y: 50%) {
text-indent: -99999em;
overflow: hidden;
text-align: left;
background: {
image: $image;
repeat: no-repeat;
position: $x $y;
}
}
.mail-icon {
@include replace-text(url("/images/mail.svg"), 0);
}.mail-icon {
text-indent: -99999em;
overflow: hidden;
text-align: left;
background-image: url("/images/mail.svg");
background-repeat: no-repeat;
background-position: 0 50%;
}关键字参数 / 指定参数
// 定义块元素内边距
@mixin block-padding($top,$right,$bottom,$left) {
padding-top: $top;
padding-right: $right;
padding-bottom: $bottom;
padding-left: $left;
}
// 使用
.container {
@include block-padding($top:12px,$right:50px,$bottom:30px,$left:0px)
}注意:参数名和参数的数量要对应,参数顺序可调整。
可变参数
参数不固定的情况
/*
定义线性渐变
@param $direction 方向
@param $gradients 颜色过渡的值列表
*/
@mixin linear-gradient($direction,$gradients...) {
background-color: nth($gradients, 1);
background-image: linear-gradient($direction,$gradients);
}
.container {
@include linear-gradient(to right, orange, yellow)
}2. 引用混合样式 @include
3. @content
@content 表示占位的意思,在使用混合指令的时候,会将指令大括号里面的内容放置到 @content 的位置,有点类似于插槽。
例子:
@mixin button-theme($color) {
background-color: $color;
border: 1px solid darken($color, 15%);
&:hover {
background-color: lighten($color, 5%);
border-color: darken($color, 10%);
}
@content
};
.button-primary {
@include button-theme(#007bff){
width: 500px;
height: 400px;
}
}
.button-secondary {
@include button-theme(#6c757d){
width: 300px;
height: 200px;
}
}.button-primary {
background-color: #007bff;
border: 1px solid #0056b3;
width: 500px;
height: 400px;
}
.button-primary:hover {
background-color: #1a88ff;
border-color: #0062cc;
}
.button-secondary {
background-color: #6c757d;
border: 1px solid #494f54;
width: 300px;
height: 200px;
}
.button-secondary:hover {
background-color: #78828a;
border-color: #545b62;
}最后我们需要说一先关于 @content 的作用域的问题。
在混合指令的局部作用域里面所定义的变量不会影响 @content 代码块中的变量,同样,在 @content 代码块中定义的变量不会影响到混合指令中的其他变量,两者之间的作用域是隔离的。
@mixin scope-test {
$test-variable: "mixin";
.mixin{
content: $test-variable
}
@content
};
.test {
$test-variable: "test";
@include scope-test {
.content {
content : $test-variable
}
}
}.test .mixin {
content: "mixin";
}
.test .content {
content: "test";
}三、@extend
在设计网页的时候通常遇到这样的情况:一个元素使用的样式与另一个元素完全相同,但又添加了额外的样式。通常会在 HTML 中给元素定义两个 class,一个通用样式,一个特殊样式。

1. 问题引入
| 标记 | 说明 |
|---|---|
| info | 信息!请注意这个信息。 |
| success | 成功!很好地完成了提交 |
| warning | 警告!请不要提交。 |
| danger | 错误!请进行一些更改。 |
所有按钮的基本样式(风格、字体大小、内边距、边框等 ...),我们通常会定义一个通用 alert 样式。
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 12px;
}不同警告单独风格
.alert-info {
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
.alert-success {
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.alert-warning {
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}
.alert-danger {
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}2. 使用继承 @extend 改进
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 12px;
}
.alert-info {
@extend .alert;
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
.alert-success {
@extend .alert;
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.alert-warning {
@extend .alert;
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}
.alert-danger {
@extend .alert;
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}3. 使用多个 @extend
定义两个类
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 12px;
}
.important {
font-weight: bold;
font-size: 14px;
}使用
.alert-danger {
@extend .alert;
@extend .important;
color: #afa;
background-color: #aaf;
border-color: #faa;
}4. @extend 多层继承
一个类可以继承另外一个类,这个类还可以被另外一个类继承。
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 12px;
}
.important {
@extend .alert;
font-weight: bold;
font-size: 14px;
}
.alert-danger {
@extend .important;
color: #afa;
background-color: #aaf;
border-color: #faa;
}5. 占位符 %
你可能发现被继承的 CSS 父类并没有被实际应用,也就是说 HTML 代码中没有使用该类,他的唯一目的就是扩展其他选择器。
对于该类,可能不希望被编译输出到最终的 CSS 文件中,它只会增加 CSS 文件的大小,永远不会被使用。
这就是占位符选择器的作用。
占位符选择器类似于类选择器,但是,它们不是以句点 (.) 开头,而是一百分号 (%) 开头。
当在 Sass 文件中使用占位符选择器时,它可以用于扩展其他选择器,但不会编译成最终的 CSS。
改写
%alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 12px;
}
.alert-info {
@extend %alert;
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
.alert-success {
@extend %alert;
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.alert-warning {
@extend %alert;
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}
.alert-danger {
@extend %alert;
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}四、@at-root
有些时候,我们可能会涉及到将嵌套规则移动到根级别(声明的时候并没有写在根级别)。这个时候就可以使用 @at-root
.parent{
color: red;
@at-root .child{
color: blue;
}
}.parent {
color: red;
}
.child {
color: blue;
}如果你想要移动的是一组规则,这个时候需要在 @at-root 后面添加一对大括号,将想要移动的这一组样式放入到大括号里面
.parent {
color: red;
@at-root {
.child {
color: blue;
}
.test {
color: pink;
}
.test2 {
color: purple;
}
}
}.parent {
color: red;
}
.child {
color: blue;
}
.test {
color: pink;
}
.test2 {
color: purple;
}第五章:函数指令
一、自定义函数
在 Sass 里面自定义函数的语法如下:
@function fn-name($params...){
@return XXX;
}具体示例如下:
@function divide($a, $b){
@return $a / $b
};
.container {
width: divide(100px, 2)
}
.container {
width: 50px;
}函数可以接收多个参数,如果不确定会传递几个参数,那么可以使用前面介绍过的不定参数的形式。
@function sum($nums...) {
$sum: 0;
@each $n in $nums {
$sum: $sum + $n;
}
@return $sum;
}
.box1 {
width: sum(1, 2, 3) + px;
}
.box2 {
width: sum(1, 2, 3, 4, 5, 6) + px;
}
.box1 {
width: 6px;
}
.box2 {
width: 21px;
}最后我们还是来看一个实际开发中的示例:
// 根据传入的 $background-color 返回适当的文字颜色
@function contrast-color($background-color) {
// 计算背景颜色的亮度
$brightness: red($background-color) * 0.299 + green($background-color) * 0.587 + blue($background-color) * 0.114;
// 根据亮度来返回黑色或者白色的文字颜色
@if $brightness > 128 {
@return #000;
} @else {
@return #fff;
}
}
.button {
$background-color: #007bff;
background-color: $background-color;
color: contrast-color($background-color);
}在上面的代码示例中,我们首先定义了一个名为 contrast-color 的函数,该函数接收一个背景颜色参数,函数内部会根据这个背景颜色来决定文字应该是白色还是黑色。
.button {
background-color: #007bff;
color: #fff;
}二、内置函数
更多函数列表参见:https://sass-lang.com/documentation/modules
中文文档:https://sass.nodejs.cn/documentation/modules
1. color (颜色函数)
RGB 函数
| 函数名和参数类型 | 函数作用 |
|---|---|
| rgb(red, green, blue) | 返回一个 16 进制颜色值 |
| rgba(red, green, blue, alpha) | 返回一个 rgba;red, green 和 blue 可被当作一个整体以颜色单词、hsl、rgb 或 16 进制形式传入 |
| red($color) | 从 $color 中获取其中红色值 |
| green($color) | 从 $color 中获取其中绿色值 |
| blue($color) | 从 $color 中获取其中蓝色值 |
| mix(color1, color2, weight?) | 按照 weight 比例,将 color1 和 color2 混合为一个新颜色 |
HSL 函数
| 函数名和参数类型 | 函数作用 |
|---|---|
| hsl( | 通过色相(hue)、饱和度(saturation)和亮度(lightness)的值创建一个颜色 |
| hsla( | 通过色相(hue)、饱和度(saturation)、亮度(lightness)和透明(alpha)的值创建一个颜色 |
| saturation($color) | 从一个颜色中获取饱和度(saturation)值 |
| lightness($color) | 从一个颜色中获取亮度(lightness)值 |
| adjust-hue( | 通过改变一个颜色的色相值,创建一个新的颜色 |
| lighten( | 通过改变颜色的亮度值,让颜色变亮,创建一个新的颜色 |
| darken( | 通过改变颜色的亮度值,让颜色变暗,创建一个新的颜色 |
| hue($color) | 从一个颜色中获取亮度色相(hue)值 |
Opacity 函数
| 函数名和参数类型 | 函数作用 |
|---|---|
| alpha(color) / opacity(color) | 获取颜色透明度值 |
| rgba(color, alpha) | 改变颜色的透明度 |
| opacify(color, amount) / fade-in(color, amount) | 使颜色更不透明 |
| transparentize(color, amount) / fade-out(color, amount) | 使颜色更加透明 |
Sass 包含很多操作颜色的函数。例如:lighten() 与 darken() 函数可用于调亮或调暗颜色
例如:
p {
height: 30px;
}
.p0 {
background-color: #5c7a29;
}
.p1 {
/*
让颜色变亮
lighten($color, $amount)
$amount 的取值在 0%-100% 之间
*/
background-color: lighten(#5c7a29, 30%);
}
.p2 {
// 让颜色变暗, 通常使用color.scale()代替该方案
background-color: darken($color: #5c7a29, $amount: 15%);
}
.p3 {
// 降低颜色透明度, 通常使用color.scale(5c7a29)代替该方案
// background-color:opacify(#5c7a29,0.5);
background-color: opacify(rgba(#5c7a29, 0.1), 0.5); // 里面小数相加不能 >=1 否则无效
}使用
<p class="p0"></p>
<p class="p1"></p>
<p class="p2"></p>
<p class="p3"></p>2. String (字符串函数)
| 函数名和参数类型 | 函数作用 |
|---|---|
quote($string) | 添加引号 |
unquote($string) | 除去引号 |
to-lower-case($string) | 变为小写 |
to-upper-case($string) | 变为大写 |
str-length($string) | 返回 $string 的长度 (汉字算一个) |
str-index(string,substring) | 返回 substring 在 string 的位置 |
str-insert(string,insert, $index) | 在 string 的 index 处插入$insert |
str-slice(string,start-at, $end-at) | 截取 string 的 start-at 和 $end-at 之间的字符串 |
注意:索引是从 1 开始的,如果书写 -1,那么就是倒着来的;两边都是闭区间。
例子
$str: "Hello world!";
.slice1{
content: str-slice($str, 1, 5)
}
.slice2{
content:str-slice($str, -1)
}编译为:
.slice1 {
content: "Hello";
}
.slice2 {
content: "!";
}3. Math (数学函数)
| 函数名和参数类型 | 函数作用 |
|---|---|
| percentage($number) | 转换为百分比形式 |
| round($number) | 四舍五入为整数 |
| ceil($number) | 数值向上取整 |
| floor($number) | 数值向下取整 |
| abs($number) | 获取绝对值 |
| min($number...) | 获取最小值 |
| max($number...) | 获取最大值 |
| random($number?:number) | 不传入值:获得 0-1 的随机数;传入正整数 n:获得 0-n 的随机整数(左开右闭) |
例子:
p {
z-index: abs($number: -16); // 取整 16
z-index: max(6,12,8,35); // 最大值 35
z-index: ceil(6.8); // 向上取整 7
opacity: random(); // 随机数 0-1
}4. List (数组函数)
| 函数名和参数类型 | 函数作用 |
|---|---|
| length($list) | 获取数组长度 |
| nth($list, n) | 获取指定下标的元素 |
| set-nth(list, n, $value) | 向 list 的 n 处插入$value |
| join(list1, list2, $separator) | 拼接 list1 和 list2;separator 为新 list 的分隔符,默认为 auto,可选择 comma、space |
| append(list, val, $separator) | 向 list 的末尾添加 val;$separator 为新 list 的分隔符,默认为 auto,可选择 comma、space |
| index(list, value) | 返回 value 值在 list 中的索引值 |
| zip($lists…) | 将几个列表结合成一个多维的列表;要求每个的列表个数值必须是相同的 |
例子:
p {
z-index: length(12px); // 1
z-index: length(12px 5px 8px); // 3
z-index: index(a b c d, c); // 3
padding: append(10px 20px, 30px); // 10px 20px 30px
color: nth($list: red blue green, $n: 2); // blue
}5. Map (字典函数)
| 函数名和参数类型 | 函数作用 |
|---|---|
| map-get(map, key) | 获取 map 中 key 对应的 $value |
| map-merge(map1, map2) | 合并 map1 和 map2,返回一个新 $map |
| map-remove(map, key) | 从 map 中删除 key,返回一个新 $map |
| map-keys($map) | 返回 map 所有的 key |
| map-values($map) | 返回 map 所有的 value |
| map-has-key(map, key) | 判断 map 中是否存在 key,返回对应的布尔值 |
| keywords($args) | 返回一个函数的参数,并可以动态修改其值 |
例子:
$font-size: (
"small": 12px,
"normal": 18px,
"large": 24px,
);
$padding: (
top: 10px,
right: 20px,
bottom: 10px,
left: 30px,
);
p {
font-size: map-get($font-size, "normal"); // 18px
@if map-has-key($padding, "right") {
padding-right: map-get($padding, "right");
}
&:after {
content: map-keys($font-size) + " " + map-values($padding) + "";
}
}6. selector (选择器函数)
选择符相关函数可对CSS选择进行一些相应的操作,例如:selector-append()可以把一个选择符附加到另一个选择符,selector-unify()将两组选择器合成一个复合选择器。
例子:
.header {
background-color: #000;
content: '' + selector-append(".a",".b",".c");
content: selector-unify("a",".disabled") + '';
}7. meta (自检函数)
| 函数名和参数类型 | 函数作用 |
|---|---|
| type-of($value) | 返回 $value 的类型 |
| unit($number) | 返回 $number 的单位 |
| unitless($number) | 判断 $number 是否没用带单位,返回对应的布尔值,没有带单位为 true |
comparable($number1, $number2) | 判断 $number1 和 $number2 是否可以做加、减和合并,返回对应的布尔值 |
| variable-exists() | 检查当前作用域中是否存在某个变量 |
| mixin-exists() | 检查某个 mixin 是否存在 |
例子:
$color:#f00;
@mixin padding($left:0,$top:0,$right:0,$bottom:0) {
padding: $top $right $bottom $left;
}
.container{
@if variable-exists(color){
color: $color;
}
@else{
content: "$color不存在";
}
@if mixin-exists(padding) {
@include padding($left:10px, $right:10px)
}
}自检函数通常用在代码的调试上
