CSS预处理器(Sass、Scss)

sass 导入@import

@import

​ Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。被导入的文件将合并编译到同一个 CSS 文件中,另外,被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。

例如:

public.scss

1
$font-base-color:#333;

index.scss

1
2
3
4
5
6
@import "public";
$color:#666;
.container{
border-color: $color;
color: $font-base-color;
}

编译后:

1
.container { border-color: #666; color: #333; }

但是如下的几种方式,都将作为普通的 CSS 语句,不会导入任何 Sass 文件

  • 文件拓展名是 .css;
  • 文件名以 http:// 开头;
  • 文件名是 url();
  • @import 包含 media queries。
1
2
3
@import "public.css";
@import url(public);
@import "http://xxx.com/xxx";

局部文件(Partials)

​ Sass源文件中可以通过@import指令导入其他Sass源文件,被导入的文件就是****局部文件****,局部文件让Sass模块化编写更加容易。

​ 如果一个目录正在被Sass程序监测,目录下的所有scss/sass源文件都会被编译,但通常不希望局部文件被编译,因为局部文件是用来被导入到其他文件的。如果不想局部文件被编译,文件名可以以下划线 (_)开头

_theme.scss

1
2
$border-color:#999;
$background-color:#f2f2f2;

index.scss

1
2
3
4
5
6
7
8
@import "public";
@import "theme";
$color:#666;
.container{
border-color: $border-color;
color: $font-base-color;
background-color: $background-color;
}

编译后:

1
.container { border-color: #999; color: #333; background-color: #f2f2f2; }

​ 可以看到,@import 引入的theme.scss,可以没有下划线(__),这是允许的,这也就意味着,同一个目录下不能同时出现两个相关名的sass文件(一个不带*,一个带_),添加下划线的文件将会被忽略。

嵌套 @import

​ 大多数情况下,一般在文件的最外层(不在嵌套规则内)使用 @import,其实,也可以将 @import 嵌套进 CSS 样式或者 @media 中,与平时的用法效果相同,只是这样导入的样式只能出现在嵌套的层中。

base.scss

1
2
3
.main-color{
color: #F00;
}

index.scss

1
2
3
.container{
@import "base";
}

最后生成

1
.container .main-color { color: #F00; }

被导入的文件不能是局部文件方式(在前面不能加_)

sass 混合指令 (Mixin Directives)

​ 混合指令(Mixin)用于定义可重复使用的样式,避免了使用无语意的 class,比如 .float-left。混合指令可以包含所有的 CSS 规则,绝大部分 Sass 规则,甚至通过参数功能引入变量,输出多样化的样式。

​ mixin是可以重用的一组CSS声明。mixin有助于减少重复代码,只需声明一次,就可在文件中引用。

​ 可以看出,mixin类似变量,不同的是变量存储值,mixin存储一组css声明。mixin可以传入参数。

定义与使用混合指令 @mixin

1
2
3
@mixin mixin-name([param1,[param2...]]) {
/* css 声明 */
}
  1. 标准形式

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义页面一个区块基本的样式
@mixin block {
width: 96%;
margin-left: 2%;
border-radius: 8px;
border:1px #f6f6f6 solid;
}
// 使用混入
.container{
.block{
@include block;
}
}

生成结果

1
2
3
4
5
6
.container .block {
width: 96%;
margin-left: 2%;
border-radius: 8px;
border: 1px #f6f6f6 solid;
}
  1. 嵌入选择器

1
2
3
4
5
6
7
8
9
10
11
12
// 定义警告字体样式,下划线(_)与横线(-)是一样的
@mixin warning-text {
.warn-text{
font-size: 12px;
color: rgb(255, 253, 123);
line-height: 180%;
}
}
// 使用混入
.container{
@include warning-text;
}

编译结果

1
2
3
4
5
.container .warn-text {
font-size: 12px;
color: #fffd7b;
line-height: 180%;
}
  1. 使用变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义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);
}
// 给指定参数指定值
.footer{
@include flex-align($aitem:center);
}
  1. 使用变量(多参数)

1
2
3
4
5
6
7
// 定义块元素内边距
@mixin block-padding($top,$right,$bottom,$left){
padding-top: $top;
padding-right: $right;
padding-bottom: $bottom;
padding-left: $left;
}
  • 使用一
1
2
3
4
// 按照参数顺序赋值
.container{
@include block-padding(10px,20px,30px,40px);
}
  • 使用二
1
2
3
4
// 可指定参数赋值
.container{
@include block-padding($left:20px, $top:10px, $bottom: 10px, $right:30px);
}

只想设置两个边:

1
2
3
4
// 可指定参数赋值
.container{
@include block-padding($left:10px, $top:10px, $bottom:0, $right:0);
}
  1. 指定默认值

1
2
3
4
5
6
7
// 定义块元素内边距,参数指定默认值
@mixin block-padding($top:0,$right:0,$bottom:0,$left:0){
padding-top: $top;
padding-right: $right;
padding-bottom: $bottom;
padding-left: $left;
}

灵活使用

1
2
3
4
5
6
7
8
9
10
11
// 可指定参数赋值
.container{
// 不带参数
//@include block-padding;

//按顺序指定参数值
//@include block-padding(10px,20px);

//给指定参数指定值
@include block-padding($left:10px,$top:20px)
}
  1. 可变参数

参数不固定的情况

1
2
3
4
5
6
7
8
9
**
*定义线性渐变
*@param $direction 方向
*@param $gradients 颜色过度的值列表
*/
@mixin linear-gradient($direction, $gradients...) {
background-color: nth($gradients,1);
background-image: linear-gradient($direction, $gradients);
}

使用

1
2
3
.table-data{
@include linear-gradient(to right,#F00, orange, yellow);
}

sass @extend(继承)

普通CSS的实现

接下来以警告框为例进行讲,解4种类型

类型说明
info信息!请注意这个信息。
success成功!很好地完成了提交。
warning警告!请不要提交。
danger错误!请进行一些更改。

所有警告框的基本样式(风格、字体大小、内边距、边框等…) ,因为我们通常会定义一个通用alert样式,类似于这样的

1
2
3
4
5
6
7
.alert{
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 12px;
}

然后定义不同警告框单独风格:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.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;
}

然后这样使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="alert alert-info">
信息!请注意这个信息。
</div>

<div class="alert alert-success">
成功!很好地完成了提交。
</div>

<div class="alert alert-warning">
警告!请不要提交。
</div>

<div class="alert alert-danger">
错误!请进行一些更改。
</div>

使用继承@extend进行改进

基本样式我们没有变,主要是各个警告框单独的样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.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;
}

这样编译后:

1
2
3
4
5
6
7
8
9
.alert, .alert-info, .alert-success, .alert-warning, .alert-danger { 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; }

使用时就不须要再写基本类了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="alert-info">
信息!请注意这个信息。
</div>

<div class="alert-success">
成功!很好地完成了提交。
</div>

<div class="alert-warning">
警告!请不要提交。
</div>

<div class="alert-danger">
错误!请进行一些更改。
</div>

使用多个@extend

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.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: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}

@extend多层继承

上面的方式还可以写成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.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: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}

占位符

你可能发现被继承的css父类并没有被实际应用,也就是说html代码中没有使用该类,它的唯一目的就是扩展其他选择器。 对于该类,可能不希望被编译输出到最终的css文件中,它只会增加CSS文件的大小,永远不会被使用。 这就是占位符选择器的作用。 占位符选择器类似于类选择器,但是,它们不是以句点(.)开头,而是以百分号(%)开头。 当在Sass文件中使用占位符选择器时,它可以用于扩展其他选择器,但不会被编译成最终的CSS。

之前的代码进行改写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
%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;
}

编译后:

1
2
3
4
5
6
7
8
9
.alert-info, .alert-success, .alert-warning, .alert-danger { 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; }

SASS 运算 (Operations)符的基本使用

赋值运算符

赋值运算符就是把一个值赋值给一个变量,通过冒号(:)的方式进行承接(很多编程语言是=),例如:

1
$font-size:16px;

也可以把一个变量赋值给另一个变量

1
2
$font-size:16px;
$h3:$font-size;

赋值的变量必须先有值

等号操作符

等号操作符用于比较两个表达式的值是否相等,所有数据类型都支持等号运算符:

符号说明
==等于
!=不等于
  1. 数字比较:
1
2
3
4
5
6
7
8
9
$theme:1;
.container {
@if $theme==1 {
background-color: red;
}
@else {
background-color: blue;
}
}
  1. 字符串比较:
1
2
3
4
5
6
7
8
9
$theme:"blue";
.container {
@if $theme !="blue" {
background-color: red;
}
@else {
background-color: blue;
}
}

所有数据类型均支持相等运算 ==!=,此外,每种数据类型也有其各自支持的运算方式。

比较运算符

比较运算符主要用于两个数值(整数与小数)间的比较,操作符有

符号说明
< (lt)小于
> (gt)大于
<= (lte)小于等于
>= (gte)大于等于

例如

1
2
3
4
5
6
7
8
9
$theme:3;
.container {
@if $theme >= 5 {
background-color: red;
}
@else {
background-color: blue;
}
}

其它语言还有字符串的比较,但这里是不行的

逻辑运算符

逻辑运算符通常用于连接多个表达式,用下真判断条件是否成立,它们有and、or、not

符号说明
and逻辑与
or逻辑或
not逻辑非

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$width:100;
$height:200;
$last:false;
div {
@if $width>50 and $height<300 {
font-size: 16px;
}
@else {
font-size: 14px;
}
@if not $last {
border-color: red;
}
@else {
border-color: blue;
}
}

数字操作符

数字操作符通常是对数字(整数或小数)进行计算,但是某些操作符(/或+)会有特殊情况,后面分开详细讲解

符号说明
+
-
*
/
%取模

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
+、-、*、/、%
线数字、百分号、css部分单位(px、pt、in...)
+
线数字与百分号或单位运算时会自动转化成相应的百分比与单位值
*/
.container {
/* ==================+ 运算===================== */
width: 50 + 20;
width: 50 + 20%;
width: 50% + 20%;
width: 10px + 20px;
width: 10pt + 20px;
width: 10pt + 20;
width: 10px + 10;
/* ==================- 运算===================== */
height: 50 - 30;
height: 10 - 30%;
height: 60% - 30%;
height: 50px - 20px;
height: 50pt - 20px;
height: 50pt - 40;
/* ==================* 运算===================== */
height: 50 * 30;
height: 10 * 30%;
/* height: 60% * 30%; 出现了两个百分号*/
/* height: 50px * 20px; 出现了两个单位*/
height: 50 * 2px;
height: 50pt * 4;
/* ==================/运算 (除完后最多只能保留一种单位)===================== */
$width: 100px;
width: 10 / 5;
width: 10px / 5px;
width: 10px / 10 * 2;
width: 20px / 2px * 5%;
width: ($width/2); // 使用变量与括号
z-index: round(10)/2; // 使用了函数
height: (500px/2); // 使用了括号
/* ==================% 运算===================== */
width: 10 % 3;
width: 50 % 3px;
width: 50px % 4px;
width: 50px % 7;
width: 50% % 7;
width: 50% % 9%;
width: 50px % 10pt; // 50px % 13.33333px
width: 50px % 13.33333px;
width: 50px + 10pt;
/* width: 50px % 5%; 单位不统一*/
}

/ 在 CSS 中通常起到分隔数字的用途,SassScript 作为 CSS 语言的拓展当然也支持这个功能,同时也赋予了 / 除法运算的功能。也就是说,如果 / 在 SassScript 中把两个数字分隔,编译后的 CSS 文件中也是同样的作用。

以下三种情况 / 将被视为除法运算符号:

  • 如果值或值的一部分,是变量或者函数的返回值
  • 如果值被圆括号包裹
  • 如果值是算数表达式的一部分

例如

1
2
3
4
5
6
7
8
$width: 1000px;
div {
font: 16px/30px Arial, Helvetica, sans-serif; // 不运算
width: ($width/2); // 使用变量与括号
z-index: round(10)/2; // 使用了函数
height: (500px/2); // 使用了括号
margin-left: 5px + 8px/2px; // 使用了+表达式
}

如果需要使用变量,同时又要确保 / 不做除法运算而是完整地编译到 CSS 文件中,只需要用 #{} 插值语句将变量包裹。

字符串运算

+ 可用于连接字符串

注意:如果有引号字符串(位于 + 左侧)连接无引号字符串,运算结果是有引号的,相反,无引号字符串(位于 + 左侧)连接有引号字符串,运算结果则没有引号。

有问题???? 如果有一个值是函数返回的,情况可能不一样

例如

1
2
3
4
.container {
content: "Foo " + Bar;
font-family: sans- + "serif";
}

三元条件函数if使用

1
2
$i:0;
@if($i==0,true,false);

SASS 插值语句 #{ }的使用

使用插值语法

1
2
3
4
5
6
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height} Helvetica,
sans-serif;
}

通过 #{} 插值语句可以在选择器、属性名、注释中使用变量:

1
2
3
4
5
6
7
8
9
10
11
12
$class-name: danger;
$attr: color;
$author:'老姚';

/*
* 这是文件的说明部分
@author: #{$author}
*/

a.#{$class-name} {
border-#{$attr}: #F00;
}

编译后

1
2
3
4
5
6
7
/*
* 这是文件的说明部分
@author: 老姚
*/
a.danger {
border-color: #F00;
}

插值语法说明

插值一般就指插入值在某个位置,该功能不是sass才有的,其实很多语言都有,例如前段的js,如果我们想输出一个带变量的值

1
2
3
var name = '张三',
age = 20;
console.log('我叫' + name + ',今年' + age + '岁!');

如果有很多变量要输出,或这个串很长的情况是非常麻烦的,所以我们可以用模板字符串输出,像这样

1
2
3
var name = '张三',
age = 20;
console.log(`我叫${name},今年${age}岁!`);

而sass中的插值用的是#{}把变量包裹起来的,变量可以是几乎任意类型的值;

什么时候会用到插值语法?

注释、选择器、属性名等有变量输出时

上面的安全便是该种情况

1
2
3
4
5
6
7
8
9
10
11
12
$class-name: danger;
$attr: color;
$author:'老姚';

/*
* 这是文件的说明部分
@author: #{$author}
*/

a.#{$class-name} {
border-#{$attr}: #F00;
}

用于调式

1
2
3
4
5
6
7
8
9
10
11
$themes:( 'light':#f00, 'dark':#000);
@function color($key) {
@if not map-has-key($themes, $key) {
@warn " $themes有key里面不包含 `#{$key}`.";
}
@return map-get($themes, $key);
}

.container {
background-color: color('light');
}

更多使用场景欢迎补充

这些情况不能使用插值语法,不可插值用于变量的一部分

1
2
3
4
5
6
7
$font-size-big: 40px;
$font-size-base: 20px;
$font-size-small: 12px;
$size:big;
.block {
font-size: $font-size-#{$size}; // Error: Undefined variable.
}

不能在混入里使用

1
2
3
4
5
6
7
8
9
@mixin base {
margin-top: 20px;
background: #F00;
}

$flag: "base";
.navigation {
@include #{$flag}; // Error: Expected identifier.
}

@import后不能使用

1
2
3
4
5
$var:'common';
@import #{var};
.block {
font-size: $font-size;
}

Sass预处理器 常见函数的基本使用

Color(颜色函数)

​ sass包含很多操作颜色的函数。例如:lighten() 与 darken()函数可用于调亮或调暗颜色,opacify()函数使颜色透明度减少,transparent()函数使颜色透明度增加,mix()函数可用来混合两种颜色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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(#5c7a29, 15%);
}

.p3 {
// 降低颜色透明度 通常使用color.scale()代替该方案
// background-color: opacify(#5c7a29,0.5);
background-color: opacify(rgba(#5c7a29, 0.1), 0.5);
}

使用

1
2
3
4
5
<p></p>
<p class="p0"></p>
<p class="p1"></p>
<p class="p2"></p>
<p class="p3"></p>

更多详细使用:https://sass-lang.com/documentation/modules/color

String(字符串函数)

​ Sass有许多处理字符串的函数,比如向字符串添加引号的quote()、获取字符串长度的string-length()和将内容插入字符串给定位置的string-insert()。

1
2
3
4
5
6
7
p {
&:after {
content: quote(这是里面的内容);
}
background-color: unquote($string: "#F00");
z-index:str-length("sass学习");
}

更多详细使用:https://sass-lang.com/documentation/modules/string

Math(数值函数)

​ 数值函数处理数值计算,例如:percentage()将无单元的数值转换为百分比,round()将数字四舍五入为最接近的整数,min()和max()获取几个数字中的最小值或最大值,random()返回一个随机数。

例如

1
2
3
4
5
6
p {
z-index: abs($number: -15); // 15
z-index: ceil(5.8); //6
z-index: max(5, 1, 6, 8, 3); //8
opacity: random(); // 随机 0-1
}

更多详细使用:https://sass-lang.com/documentation/modules/math

List函数

List函数操作List,length()返回列表长度,nth()返回列表中的特定项,join()将两个列表连接在一起,append()在列表末尾添加一个值。

例如:

1
2
3
4
5
6
7
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
}

更多详细使用:https://sass-lang.com/documentation/modules/list

Map函数

Map函数操作Map,map-get()根据键值获取map中的对应值,map-merge()来将两个map合并成一个新的map,map-values()映射中的所有值。

1
2
3
4
5
6
7
8
9
10
11
$font-sizes: ("small": 12px, "normal": 18px, "large": 24px);
$padding:(top:10px, right:20px, bottom:10px, left:30px);
p {
font-size: map-get($font-sizes, "normal"); //18px
@if map-has-key($padding, "right") {
padding-right: map-get($padding, "right");
}
&:after {
content: map-keys($font-sizes) + " "+ map-values($padding) + "";
}
}

更多详细使用:https://sass-lang.com/documentation/modules/map

selector选择器函数

​ 选择符相关函数可对CSS选择进行一些相应的操作,例如:selector-append()可以把一个选择符附加到另一个选择符,selector-unify()将两组选择器合成一个复合选择器。

例如

1
2
3
4
5
.header {
background-color: #000;
content: selector-append(".a", ".b", ".c") + '';
content: selector-unify("a", ".disabled") + '';
}

更多详细使用:https://sass-lang.com/documentation/modules/selector

自检函数

​ 自检相关函数,例如:feature-exists()检查当前Sass版本是否存在某个特性,variable-exists()检查当前作用域中是否存在某个变量,mixin-exists()检查某个mixin是否存在。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$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);
}
}

自检函数通常用在代码的调试上