0%

scss

scss快速入门:



准备工作

写在最前面:在认识之前需要安装下sass;在这里我是在react脚手架中安装运行,在其他环境中可能安装方式不同,还有可能需要配置;但是不影响对scss语法的介绍使用。

scss需要经过编译为css才能被浏览器识别,我这里只做一个小demo,直接使用react脚手架进行编译。

首先安装node-scss:

1
2
npm i node-sass -v 
yarn add node-sass -v

正式开始

1.变量使用

SCSS中的变量以$开头。

scss变量类似JS语法,可分为:

  • 全局变量 —- 在大括号之外声明的变量
  • 局部变量 —- 在括号中之内声明的变量
1
2
3
4
5
6
$border-color:#aaa; //声明变量  全局

.container {
$border-width:1px; // 声明变量 局部
border:$border-width solid $border-color; //使用变量
}

编译后的CSS

1
2
3
.container {
border:1px solid #aaa; //使用变量
}

我们可以把SCSS看做一个模板引擎,编译的过程中用变量的值去替代变量所占据的位置。

注意:SCSS中变量名使用中划线或下划线都是指向同一变量的,上文中定义了一个变量$border-color,这时再定义一个变量$border_color:#ccc,他们指向同一个变量,.container的值会被第二次定义的变量覆盖。

1
2
3
4
5
6
7
8
9
10
$border-color:#aaa; //声明变量
$border_color:#ccc;
.container {
$border-width:1px;
border:$border-width solid $border-color; //使用变量
}
编译后的CSS
.container {
border:1px solid #ccc; //使用变量
}

这个例子中我们要知道

(1)变量名使用中划线或下划线都是指向同一变量的。

(2)后定义的变量声明会被忽略,但赋值会被执行,这一点和ES5中var声明变量是一样的。

2.嵌套规则

我们先来看一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*css*/
.container ul {
border:1px solid #aaa;
list-style:none;
}

.container ul:after {
display:block;
content:"";
clear:both;
}

.container ul li {
float:left;
}

.container ul li>a {
display:inline-block;
padding:6px 12px;
}

这是一个让列表元素横向排列的例子,我们在这个例子中写了很多重复的代码,.container写了很多遍,下面我将用SCSS简写上面的例子。

2.1嵌套选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*scss*/
.container ul {
border:1px solid #aaa;
list-style:none;

li {
float:left;
}

li>a {
display:inline-block;
padding:6px 12px;
}
}

.container ul:after {
display:block;
content:"";
clear:both;
}

这里我们可以将公共的父元素提取出来。

2.2嵌套中的父级选择器**&**

SCSS提供了一个选择器可以选中当前元素的父元素,使用&表示,下面用父级选择器继续简化代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*scss*/
.container ul {
border:1px solid #aaa;
list-style:none;

li {
float:left;
}

li>a {
display:inline-block;
padding:6px 12px;
}
// 只能在嵌套内部使用父级选择器
&:after {
display:block;
content:"";
clear:both;
}
}

2.3嵌套组合选择器

在嵌套规则中可以写任何css代码,包括群组选择器(,),子代选择器(>),同层相邻组合选择器(+)、同层全体组合选择器(~)等等,下面继续将自带选择器简化掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*scss*/
.container ul {
border:1px solid #aaa;
list-style:none;

li {
float:left;

>a {
display:inline-block;
padding:6px 12px;
}
}

&:after {
display:block;
content:"";
clear:both;
}
}

子代选择器可以写在外层选择器右边(如下述例子)也可以写在内层选择器左边(如上述例子)。

1
2
3
4
5
6
li >{ 
a {
display:inline-block;
padding:6px 12px;
}
}

2.4嵌套属性

先看一个例子

1
2
3
4
5
6
/*css*/
li {
border:1px solid #aaa;
border-left:0;
border-right:0;
}

这个例子中我们只需要两条边框,使用SCSS重写一遍。

1
2
3
4
5
6
7
/*scss*/
li {
border:1px solid #aaa {
left:0;
right:0;
}
}

scss识别一个属性以分号结尾时则判断为一个属性,以大括号结尾时则判断为一个嵌套属性,规则是将外部的属性以及内部的属性通过中划线连接起来形成一个新的属性。

3.导入SCSS文件

大型项目中css文件往往不止一个,css提供了@import命令在css内部引入另一个css文件,浏览器只有在执行到@import语句后才会去加载对应的css文件,导致页面性能变差,故基本不使用。SCSS中的@import命令跟原生的不太一样,后续会讲解到。

3.1导入变量的优先级问题-变量默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
/*App1.scss*/
$border-color:#aaa; //声明变量
@import App2.scss; //引入另一个SCSS文件
.container {
border:1px solid $border-color; //使用变量
}
/*App2.scss*/
$border-color:#ccc; //声明变量

/*生成的css文件*/
.container {
border:1px solid #ccc; //使用变量
}

这可能并不是我们想要的,有时候我们希望引入的某些样式不更改原有的样式,这时我们可以使用变量默认值。

1
2
3
4
5
6
7
8
9
10
11
12
13
/*App1.scss*/
$border-color:#aaa; //声明变量
@import App2.scss; //引入另一个SCSS文件
.container {
border:1px solid $border-color; //使用变量
}
/*App2.scss*/
$border-color:#ccc !default; //声明变量

/*生成的css文件*/
.container {
border:1px solid #aaa; //使用变量
}

导入的文件App2.scss只在文件中不存在$border-color时起作用,若App1.scss中已经存在了$border-color变量,则App2.scss中的$border-color不生效。

!default只能使用与变量中。

3.2嵌套导入

上一个例子中我们是在全局中导入的App2.scss,现在我们在为App2.scss添加一些内容,并在局部中导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*App1.scss*/
$border-color:#aaa; //声明变量
.container {
@import App2.scss; //引入另一个SCSS文件
border:1px solid $border-color; //使用变量
}
/*App2.scss*/
$border-color:#ccc !default; //声明变量
p {
margin:0;
}

/*生成的css文件*/
.container {
border:1px solid #aaa; //使用变量
}
.container p {
margin:0;
}

可以看得出来,就是将App2.scss中的所有内容直接写入到App1.scss的.container选择器中。

3.3 使用原生@import

前面我们说到基本不使用原生@import,但某些情况下我们不得不使用原生@import时了,SCSS也为我们处理了这种情况,直接导入css文件即可。

1
@import 'App.css';

4.注释

SCSS中的注释有两种

(1)/注释/:这种注释会被保留到编译后的css文件中。

(2)//注释:这种注释不会被保留到编译后生成的css文件中。

5.混合器(函数)

5.1声明一个函数

使用@mixin指令声明一个函数,看一下自己的css文件,有重复的代码片段都可以考虑使用混合器将他们提取出来复用。

1
2
3
4
5
6
@mixin border-radius{
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
color:red;
}

混合器作用域内的属性都是return的值,除此之外,还可以为函数传参数。

1
2
3
4
5
6
@mixin get-border-radius($border-radius,$color){
-moz-border-radius: $border-radius;
-webkit-border-radius: $border-radius;
border-radius: $border-radius;
color:$color;
}

也可以设置混合器的默认值。

1
2
3
4
5
6
@mixin get-border-radius($border-radius:5px,$color:red){
-moz-border-radius: $border-radius;
-webkit-border-radius: $border-radius;
border-radius: $border-radius;
color:$color;
}

5.2使用函数

使用函数的关键字为@include

1
2
3
4
5
6
7
8
9
10
11
.container {
border:1px solid #aaa;
@include get-border-radius; //不传参则为默认值5px
@include get-border-radius(10px,blue); //传参
}
/*多个参数时,传参指定参数的名字,可以不用考虑传入的顺序*/
.container {
border:1px solid #aaa;
@include get-border-radius; //不传参则为默认值5px
@include get-border-radius($color:blue,$border-radius:10px); //传参
}

我们可能会想到,直接将混合器写成一个class不就行了,但是写成一个class的时候是需要在html文件中使用的,而使用混合器并不需要在html文件中使用class既可达到复用的效果。

tips:混合器中可以写一切scss代码。

6.继承

继承是面向对象语言的一大特点,可以大大降低代码量。

6.1定义被继承的样式

1
2
3
4
5
6
%border-style {
border:1px solid #aaa;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}

使用%定义一个被继承的样式,类似静态语言中的抽象类,他本身不起作用,只用于被其他人继承。

6.2继承样式

通过关键字@extend即可完成继承。

1
2
3
.container {
@extend %border-style;
}

上述例子中看不出混合器与继承之间的区别,那么下一个例子可以看出继承与混合器之间的区别。

1
2
3
4
5
6
7
.container {
@extend %border-style;
color:red;
}
.container1 { //继承另一个选择器
@extend .container;
}

7.其他

7.1操作符

SCSS提供了标准的算术运算符,例如+、-、*、/、%。

1
2
3
4
/*SCSS*/
width: 600px / 960px * 100%;
/*编译后的CSS*/
width: 62.5%;