什么是Sass
Sass 是对 CSS 的扩展,是一种CSS预处理器,让 CSS 语言更强大、优雅。 它允许你使用变量、嵌套规则、 mixins、导入等众多功能, 并且完全兼容 CSS 语法看, 使得CSS的开发,变得简单和可维护。
Sass安装
在Ruby环境下执行
gem install sass
编译(使用)
单文件转换
sass style.scss style.css
单文件监听命令
sass --watch style.scss:style.css
文件夹监听命令
sass --watch sassDir:cssDir
css 文件转换成scss/sass文件
sass-convert style.css style.sass
sass-convert style.css style.scss
我们一般常用的有--style,--sourcemap,--debug-info等。
sass --watch style.scss:style.css --style compact
sass --watch style.scss:style.css --sourcemap
sass --watch style.scss:style.css --style expanded --sourcemap
sass --watch style.scss:style.css --debug-info
- style表示解析后的css是什么格式,有四种取值分别为:nested,expanded,compact,compressed。
- sourcemap表示开启sourcemap调试。开启sourcemap调试后,会生成一个后缀名为.css.map文件。
- debug-info表示开启debug信息,升级到3.3.0之后因为sourcemap更高级,这个debug-info就不太用了。
四种style生成后的css
// nested
#main {
color: #fff;
background-color: #000; }
#main p {
width: 10em; }
.huge {
font-size: 10em;
font-weight: bold;
text-decoration: underline; }
// expanded
#main {
color: #fff;
background-color: #000;
}
#main p {
width: 10em;
}
.huge {
font-size: 10em;
font-weight: bold;
text-decoration: underline;
}
// compact
#main { color: #fff; background-color: #000; }
#main p { width: 10em; }
.huge { font-size: 10em; font-weight: bold; text-decoration: underline; }
// compressed
#main{color:#fff;background-color:#000}#main p{width:10em}.huge{font-size:10em;font-weight:bold;text-decoration:underline}
基本使用
注释
SASS共有两种注释风格。
标准的CSS注释 /* comment */
,会保留到编译后的文件。
单行注释 // comment
,只保留在SASS源文件中,编译后被省略。
在/*后面加一个感叹号,表示这是"重要注释"。即使是压缩模式编译,也会保留这行注释,通常可以用于声明版权信息。
/*!
重要注释!
*/
嵌套规则(Nested Rules)
SASS允许选择器嵌套,比如下面代码
#a {
.a-1{
background:yellow;
.child{
font-size:12px;
.child-1{
color:red
}
}
}
}
编译后的结果:
#a .a-1 {
background: yellow;
}
#a .a-1 .child {
font-size: 12px;
}
#a .a-1 .child .child-1 {
color: red;
}
引用父选择符: & ==> parent selector
& 在编译时将被替换为父选择符,输出到 CSS 中,多用于伪类,如 a:hover , a:active , a:visited , a:first-letter , a:last-child等,比如下面代码:
.hello {
.dropdown{
display: none;
}
&:hover {
.dropdown{
display: block;
}
}
}
编译后的结果:
.hello .dropdown {
display: none;
}
.hello:hover .dropdown {
display: block;
}
属性嵌套
主要用于复合属性,比如background、font等
.funky {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
border: {
radius:20px;
color:red;
}
}
编译后的结果:
.funky {
font-family: fantasy;
font-size: 30em;
font-weight: bold;
border-radius: 20px;
border-color: red;
}
变量(Variables)
SASS允许使用变量,所有变量以$开头。写法就像CSS一样
$width: 10px;
#main {
width: $width;
}
作用域
变量支持块级作用域,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不在嵌套规则内定义的变量则可在任何地方使用(全局变量)。将局部变量转换为全局变量可以添加 !global 声明:
$width: 10px;
.p {
$width: 30px;
.a{
width: $width
}
}
编译结果为:
.p .a {
width: 30px;
}
插值(Interpolation)
如果变量需要镶嵌在字符串之中,就必须需要写在#{}(插值Interpolation)之中,比如:
$name: foo;
$attr: border;
p.#{$name} {
#{$attr}-color: blue;
content: "hello world #{$name}"
}
运算
Sass支持数字的标准运算(加 +、减 -、乘 *、除 /和取模 %)
p {
width: (1em + 2em) * 3;
}
//也可以写成这样
p {
width: (1 + 2em) * 3;
}
//或者这样
p {
width: (1em + 2) * 3;
}
编译后的结果:
p {width: 9em;}
除法运算
在以下三种情况中,/ 会被解释为除法运算。 这已经覆盖了绝大多数真正使用除法运算的情况:
- 如果数值或它的任意部分是存储在一个变量中或是函数的返回值。
- 如果数值被圆括号包围。
- 如果数值是另一个数学表达式的一部分
p {
font: 10px/8px; // 纯 CSS,不是除法运算
$width: 1000px;
width: $width/2; // 使用了变量,是除法运算
width: round(1.5)/2; // 使用了函数,是除法运算
height: (500px/2); // 使用了圆括号,是除法运算
margin-left: 5px + 8px/2px; // 使用了加(+)号,是除法运算
}
编译后的结果:
p {
font: 10px/8px; //没有进行编译
width: 500px;
width: 1;
height: 250px;
margin-left: 9px;
}
如果你希望在编译后的 CSS 中使用变量和 /, 你可以用 #{} 包住变量。 例如:
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height};
}
编译后的结果:
p {
font: 12px/30px;
}
颜色运算
p {
color: #123123 + #040506;
}
编译后的结果:
p {
color: #163629;
}
在文本字符串中,#{} 形式的表达式可以被用来在字符串中添加动态值:
空值会被视作空字符串:
p:before {
content: "I ate #{5 + 10} pies!";
}
$value: null;
p:before {
content: "I ate #{$value} pies!";
}
编译后的结果:
p:before {
content: "I ate 15 pies!";
}
p:before {
content: "I ate pies!";
}
规则和指令(directive )
(导入)@import
Sass 扩展了 CSS 的 @import 规则,让它能够引入 scss 和sass 文件,Sass的@import规则和CSS的有所不同,编译时会将@import的scss文件合并进来只生成一个CSS文件。但是如果你在Sass文件中导入css文件如@import 'reset.css',那效果跟普通CSS导入样式文件一样,导入的css文件不会合并到编译后的文件中,而是以@import方式存在。
用法如下:
@import "basic.scss";
还可以嵌套使用,相当于个编译后的basic .css加了一个命名空间,
.example {
@import "basic.scss";
}
编译后的结果:
.example #a .a-1 {
background: yellow;
}
.example #a .a-1 .child {
font-size: 12px;
}
.example #a .a-1 .child .child-1 {
color: red;
}
媒体查询(@media)
Sass 中 @media 指令与 CSS 中用法一样,只是增加了一点额外的功能:允许其在 CSS 规则中嵌套。如果 @media 嵌套在 CSS 规则内,编译时,@media 将被编译到文件的最外层,包含嵌套的父选择器。这个功能让 @media 用起来更方便,不需要重复使用选择器,也不会打乱 CSS 的书写流程。
.father{
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
.hello{
font-size:20px
}
}
}
}
编译后的结果:
.father .sidebar {
width: 300px;
}
@media screen and (orientation: landscape) {
.father .sidebar {
width: 500px;
}
.father .sidebar .hello {
font-size: 20px;
}
}
继承(@extend)
- 简单继承
Sass中,选择器继承可以让选择器继承另一个选择器的所有样式,并联合声明。使用选择器的继承,要使用关键词@extend,后面紧跟需要继承的选择器。
比如:
.error {
border: 1px #f00;
&.intrusion {
background-image: url("/image/hacked.png");
}
}
.seriousError {
@extend .error;
}
编译后的结果:
.error, .seriousError, {
border: 1px #f00;
}
.error.intrusion {
background-image: url("/image/hacked.png");
}
- 多元素继承(Multiple Extends)
.error {
border: 1px #f00;
background-color: #fdd;
}
.attention {
font-size: 3em;
background-color: #ff0;
}
.seriousError {
@extend .error;
@extend .attention;
border-width: 3px;
}
编译后的结果:
.error, .seriousError {
border: 1px #f00;
background-color: #fdd;
}
.attention, .seriousError {
font-size: 3em;
background-color: #ff0;
}
.seriousError {
border-width: 3px;
}
- 链式继承(Chaining Extends)
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.criticalError {
@extend .seriousError;
position: fixed;
top: 10%;
bottom: 10%;
left: 10%;
right: 10%;
}
编译后的结果:
.error, .seriousError, .criticalError {
border: 1px #f00;
background-color: #fdd;
}
.seriousError, .criticalError {
border-width: 3px;
}
.criticalError {
position: fixed;
top: 10%;
bottom: 10%;
left: 10%;
right: 10%;
}
从编译后的CSS中不难看出,类名“.error”变成了群组选择,添加了类名“.seriousError”和类名“.criticalError”。而类名“.seriousError”变成了群组选择,添加了类名“.criticalError”。这就叫做链式继承。
混合(@mixin)
Sass中使用@mixin声明混合,可以传递参数,参数名以$符号开始,多个参数以逗号分开,也可以给参数设置默认值。声明的@mixin通过@include来调用。
- 使用
通过@mixin定义混合
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
通过@include调用定义的混合
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
```
编译后得到:
```
.page-title {
font-family: Arial;
font-size: 20px;
font-weight: bold;
color: #ff0000;
padding: 4px;
margin-top: 10px;
}
```
- 带参数的混合
```
@mixin sexy-border($color:blue, $width:20px) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
//不传参,使用默认参数
p { @include sexy-border;}
//传参数
p { @include sexy-border(green, 10px); }
```
```
//不传参,使用默认参数
p {
border-color: blue;
border-width: 20px;
border-style: dashed;
}
//传参数
p {
border-color: green;
border-width: 10px;
border-style: dashed;
}
```
- 多组值参数mixin
如果一个参数可以有多组值,如box-shadow、transition等,那么参数则需要在变量后加三个点表示,如$shadow...,比如:
```
@mixin box-shadow($shadow...) {
-webkit-box-shadow:$shadow;
box-shadow:$shadow;
}
.box{
border:1px solid #ccc;
@include box-shadow(0 2px 2px rgba(0,0,0,.3),0 3px 3px rgba(0,0,0,.3),0 4px 4px rgba(0,0,0,.3));
}
```
编译后的结果:
```
.box{
border:1px solid #ccc;
-webkit-box-shadow:0 2px 2px rgba(0,0,0,.3),0 3px 3px rgba(0,0,0,.3),0 4px 4px rgba(0,0,0,.3);
box-shadow:0 2px 2px rgba(0,0,0,.3),0 3px 3px rgba(0,0,0,.3),0 4px 4px rgba(0,0,0,.3);
}
```
#### 条件指令
###### @if: @if可一个条件单独使用,也可以和@else或者@else if 结合多条件使用
```
p {
@if 1 + 1 == 2 { border: 1px solid; }
@if true {background-image:url('')}
@if 5 < 3 { border: 2px dotted; }
@if null { border: 3px double; }
}
$type: monster;
p {
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
```
编译后的结果:
```
p {
border: 1px solid;
background-image: url("");
}
p {
color: green;
}
```
#### 循环指令
###### @for
for循环有两种形式,分别为:@for $var from through 和@for $var from to 。$i表示变量,start表示起始值,end表示结束值,这两个的区别是关键字through表示包括end这个数,而to则不包括end这个数。
```
/*from ... through*/
@for $i from 1 through 3 { //1,2,3
.item-#{$i} { width: 2em * $i; }
}
###
/*from ... to*/
@for $i from 1 to 3 { //1,2
.item-to-#{$i} { width: 2em * $i; }
}
```
编译后的结果:
```
/*from ... through*/
.item-1 {
width: 2em;
}
.item-2 {
width: 4em;
}
.item-3 {
width: 6em;
}
/*from ... to*/
.item-to-1 {
width: 2em;
}
.item-to-2 {
width: 4em;
}
```
###### @each
语法为:@each $var in 。其中$var表示变量。
```
//单字段
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
//多字段
$animal-data: (puma, black, default),(sea-slug, blue, pointer),(egret, white, move);
@each $animal, $color, $cursor in $animal-data {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
```
编译结果为:
```
//单字段
.puma-icon {
background-image: url("/images/puma.png");
}
.sea-slug-icon {
background-image: url("/images/sea-slug.png");
}
.egret-icon {
background-image: url("/images/egret.png");
}
.salamander-icon {
background-image: url("/images/salamander.png");
}
//多字段
.puma-icon {
background-image: url('/images/puma.png');
border: 2px solid black;
cursor: default;
}
.sea-slug-icon {
background-image: url('/images/sea-slug.png');
border: 2px solid blue;
cursor: pointer;
}
.egret-icon {
background-image: url('/images/egret.png');
border: 2px solid white;
cursor: move;
}
```
###### @while
@while和@for指令很相似,只要@while后面的条件为true就会执行。
```
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
```
编译结果为:
```
.item-6 {
width: 12em;
}
.item-4 {
width: 8em;
}
.item-2 {
width: 4em;
}
```
### 自定义函数
```
$grid-width: 40px;
$gutter-width: 10px;
@function test($a){
@return $a+10
}
@function grid-width($n) {
$hello:1px ;
@for $i from 1 through $n{
$hello:$hello+$i
}
@if $hello > 10 {
$hello:15px
}
@return $hello + test(2)
}
#sidebar { width: grid-width(5); }
```
编译结果为:
```
#sidebar {
width: 27px;
}
```
**关于应用场景的思考:**
[SASS应用场景的思考](https://segmentfault.com/a/1190000009466690)