CSS预处理器-Sass

Sass

简介

css 预处理器 用一种专门的编程语言,进行 Web 页面样式设计,然后编译成正常的 CSS 文件,可以让你的 CSS 更加简洁,适应性更强,可读性更佳,更易于维护。

Sass 是采用 Ruby 语言编写的一款 CSS 预处理语言,也是因为如此,其延续了 Ruby 的书写规范,书写 Sass 时不带有大括号和分号,主要依靠严格的缩进方式来控制。

SCSSSass 的新语法规则,与之前的文件扩展名不同,一个以“.scss”为后缀,一个以“.sass”为后缀,由于 SCSS 的语法书写与 CSS 的书写方式非常类似,所以可以大幅度提高 CSS 的开发效率。

安装与编译

  • sass安装(Mac)

    1
    2
    3
    brew install ruby //先安装ruby
    sudo gem install saa //再安装sass
    sass -v //检查有没有安装成功
  • sass更新

    1
    gem update sass //更新sass
  • sass删除

    1
    gem uninstall sass //删除sass
  • sass编译

    1
    2
    3
    sass <sass文件路径>/style.scss:<css文件路径>/style.css //单文件编译
    sass <sass文件路径>/:<css文件路径>/ //多文件编译
    sass --watch <sass文件路径>/style.scss:<css文件路径>/style.css //自动检测代码变化并进行编译
  • sass不同风格的输出方法

    1. 嵌套输出方式 –style nested

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      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. 展开输出方式 –style expanded

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      nav ul {
      margin: 0;
      padding: 0;
      list-style: none;
      }
      nav li {
      display: inline-block;
      }
      nav a {
      display: block;
      padding: 6px 12px;
      text-decoration: none;
      }
    3. 紧凑输出方式 –style compact

      1
      2
      3
      nav ul { margin: 0; padding: 0; list-style: none; }
      nav li { display: inline-block; }
      nav a { display: block; padding: 6px 12px; text-decoration: none; }
    4. 压缩输出方式 –style compressed

      1
      nav ul{margin:0;padding:0;list-style:none}nav li{display:inline-block}nav a{display:block;padding:6px 12px;text-decoration:none}
  • sass调试
    浏览器支持“sourcemap”功能即可。早一点的版本,需要在编译的时候添加“–sourcemap” 参数

基本语法

  • 变量

    1
    2
    3
    // http://sassmeister.com/ 在线测试sass
    $width: 300px;
    $height: 200px !default; // 默认值,在默认变量之前重新声明即可覆盖
  • 局部变量与全局变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $color: orange !default;// 定义全局变量(在选择器、函数、混合宏...的外面定义的变量)
    .block {
    color: $color; // 调用全局变量
    }
    em {
    $color: red; // 定义局部变量
    a {
    color: $color; // 调用局部变量
    }
    }
    span {
    color: $color; // 调用全局变量
    }
  • 嵌套

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 选择器嵌套
    nav {
    a {
    color: red;

    header & { // & 代表 nav a,引用父元素
    color: green;
    }
    }
    }

    // 属性嵌套
    .box {
    border: { // 注意冒号不能省
    top: 1px solid red;
    bottom: 1px solid green;
    }
    }
  • 混合宏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 声明
    @mixin border-radius{
    -webkit-border-radius: 5px;
    border-radius: 5px;
    }
    // 调用
    button {
    @include border-radius;
    }

    不足之处,不能智能的将相同的样式代码块合并在一起,但可以传递参数

  • 继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    .btn {
    border: 1px solid #ccc;
    padding: 6px 10px;
    font-size: 14px;
    }

    .btn-primary {
    background-color: #f36;
    color: #fff;
    @extend .btn;
    }

    .btn-second {
    background-color: orange;
    color: #fff;
    @extend .btn;
    }

    可以继承类样式块中所有的样式代码,并且可以将选择器合并在一起形成组合选择器。另外可以使用 % 占位符声明需要调用的css代码,这样不被 @extend 调用就不会产生任何代码

  • 插值#{}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // .scss
    $properties: (margin, padding);
    @mixin set-value($side, $value) {
    @each $prop in $properties {
    #{$prop}-#{$side}: $value;
    }
    }
    .login-box {
    @include set-value(top, 14px);
    }

    // .css
    .login-box {
    margin-top: 14px;
    padding-top: 14px;
    }
  • 注释

    • 标准的 CSS 注释 / comment /,会保留到编译后的文件中。
    • 单行注释 // comment,只保留在sass源文件中。
    • /! important comment /重要注释,即使是压缩编译也会保留,通常用来声明版权信息。
  • 数据类型

    • 数字:1, 2, 10px;
    • 字符串: 有引号或无引号的字符串,如:”foo”,baz,!important;
    • 颜色:blue,#04a3f9,rgba(255,0,0,.5);
    • 布尔值:true,false;
    • 空值:null;
    • 值列表:用空格或逗号分开,如:1.5em 1em 0 2em,Helvetica, Arial, sans-serif;

运算

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
// 加法
.box {
width: 20px + 8in; // 注意不同类型的单位做运算会报错
}

// 减法
$full-width: 960px;
$sidebar-width: 200px;

.content {
width: $full-width - $sidebar-width;
}

// 乘法
.box {
width: 10px * 2; // 注意不同类型的单位做运算会报错
}

// 除法
p {
font: 10px/8px; // 纯 CSS,不是除法运算
$width: 1000px;
width: $width/2; // 使用了变量,是除法运算
width: round(1.5)/2; // 使用了函数,是除法运算
height: (500px/2); // 使用了圆括号,是除法运算
margin-left: 5px + 8px/2px; // 使用了加(+)号,是除法运算
width: (1000px / 100px); // 编译之后为 width: 10;
}

控制命令

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*
@if
@if 指令是一个 SassScript,可以根据条件处理样式,除了 @if 外,还可以配合 @else if 和 @else 一起使用
*/
@mixin blockOrHidden($boolean:true) {
@if $boolean {
@debug "$boolean is #{$boolean}";
display: block;
}
@else {
@debug "$boolean is #{$boolean}";
display: none;
}
}

.block {
@include blockOrHidden;
}

.hidden{
@include blockOrHidden(false);
}

/*
@for
@for $i from <start> through <end> // 包括 end
@for $i from <start> to <end> // 不包括 end
*/
@for $i from 1 through 3 {
.item-#{$i} { width: 2em * $i; }
}

@for $i from 1 to 3 {
.item-#{$i} { width: 2em * $i; }
}

/*
@while
*/
$types: 4;
$type-width: 20px;

@while $types > 0 {
.while-#{$types} {
width: $type-width + $types;
}
$types: $types - 1;
}

/*
@each
@each $var in <list> // <list>就是一个列表
*/
$list: adam john wynn mason kuroir;

@mixin author-images {
@each $author in $list {
.photo-#{$author} {
background: url("/images/avatars/#{$author}.png") no-repeat;
}
}
}

.author-bio {
@include author-images;
}

函数

  • 字符串函数

    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
    51
    52
    53
    54
    55
    56
    57
    /*
    unquote()函数
    只能删除字符串最前和最后的引号,无法删除中间的引号,没有引号则返回字符串本身
    */
    .test1 {
    content: unquote('Hello Sass!') ; // Hello Sass!
    }
    .test2 {
    content: unquote("'Hello Sass!"); // 'Hello Sass!
    }
    .test3 {
    content: unquote("I'm Web Designer"); // I'm Web Designer
    }
    .test4 {
    content: unquote("'Hello Sass!'"); // 'Hello Sass!'
    }
    .test5 {
    content: unquote('"Hello Sass!"'); // "Hello Sass!"
    }
    .test6 {
    content: unquote(Hello Sass); // Hello Sass
    }

    /*
    quote()函数
    用来给字符串添加引号
    */
    .test1 {
    content: quote('Hello Sass!'); // "Hello Sass!"
    }
    .test2 {
    content: quote("Hello Sass!"); // "Hello Sass!"
    }
    .test3 {
    content: quote(ImWebDesigner); // "ImWebDesigner"
    }
    .test4 {
    content: quote(' '); // ""
    }

    /*
    to-upper-case()函数
    将字符串小写字母转换成大写字母
    */
    .test {
    text: to-upper-case(aaaaa); // AAAAA
    text: to-upper-case(aA-aAAA-aaa); // AA-AAAA-AAA
    }

    /*
    to-lower-case()函数
    将字符串大写字母转换成小写字母
    */
    .test {
    text: to-upper-case(AAAAA); // aaaaa
    text: to-upper-case(aA-aAAA-aaa); // aa-aaaa-aaa
    }
  • 数字函数

    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
    51
    52
    53
    54
    55
    56
    /*
    percentage($value)
    将一个不带单位的数转换成百分比值
    */
    .footer {
    width: percentage(.2) // 20%
    }

    /*
    round($value)
    将数值四舍五入,转换成一个最接近的整数
    */
    .footer {
    width:round(12.3px) // 12px
    }

    /*
    ceil($value)
    将大于自己的小数转换成下一位整数
    */
    .footer {
    width:ceil(12.3px); // 13px
    }

    /*
    floor($value)
    将一个数去除小数部分
    */
    .footer {
    width:floor(12.3px); // 12px
    }

    /*
    abs($value)
    返回一个数的绝对值
    */
    .footer {
    width:abs(-12.3px); // 12.3px
    }

    /*
    min($numbers…)
    找出几个数值之间的最小值
    */
    min(1px,5px) // 1px

    /*
    max($numbers…)
    找出几个数值之间的最大值
    */
    max(1px,5px) // 5px

    /*
    random(): 获取随机数
    */
    random() // 0.13921
  • 列表函数

    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
    /*
    length($list)
    返回一个列表的长度值
    */
    length(10px 20px (border 1px solid) 2em)// 4

    /*
    nth($list, $n)
    返回一个列表中指定的某个标签值
    */
    .author-bio {
    width: nth(100px 200px 300px, 2); // 200px
    }
    /*
    join($list1, $list2, [$separator])
    将两个列给连接在一起,变成一个列表
    */
    join((blue green),(red,orange),comma) //(#0000ff, #008000, #ff0000, #ffa500)

    /*
    append($list1, $val, [$separator])
    将某个值放在列表的最后
    */
    append((blue, green),red,space) // (#0000ff #008000 #ff0000)

    /*
    zip($lists…)
    将几个列表结合成一个多维的列表
    */
    // 1px solid green, 2px dashed blue, 3px dotted red
    zip(1px 2px 3px,solid dashed dotted,green blue red)

    /*
    index($list, $value)
    返回一个值在列表中的位置值
    */
    index(1px solid red, solid) // 2
  • Introspection函数

    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
    /*
    type-of()
    返回值:number, string, bool, color
    */
    type-of(#fff) // "color"

    /*
    unit()
    获取一个值所使用的单位
    */
    unit(1em) // em

    /*
    unitless()
    判断一个值是否带有单位
    */
    unit(1em) // true

    /*
    comparable()
    判断两个数是否可以进行“加”,“减”以及合并
    */
    comparable(2px, 1cm) // true
    comparable(2px, 1rem) // false

    /*
    miscellaneous函数
    if($condition, $if-true, $if-false)
    */
    if(true, 1px, 2px) // 1px

    /*
    map,数据地图,也称其为数组
    */
    $map: (
    $key1: value1,
    $key2: value2,
    $key3: value
    );
  • Maps函数

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    $social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
    );

    /*
    map-get($map,$key)
    根据给定的 key 值,返回 map 中相关的值
    */
    .btn-dribble{
    color: map-get($social-colors,facebook); // color: #3b5998;
    }

    /*
    map-merge($map1,$map2)
    将两个 map 合并成一个新的 map,$map2 会覆盖 $map1 中同名$key
    */
    $color: (
    text: #f36,
    link: #f63,
    border: #ddd,
    backround: #fff
    );
    $typo:(
    font-size: 12px,
    line-height: 1.6,
    border: #ccc,
    background: #000
    );

    $newmap: map-merge($color,$typo);

    $newmap:(
    text: #f36,
    link: #f63,
    font-size: 12px,
    line-height: 1.6,
    border: #ccc,
    background: #000
    );
    /*
    map-remove($map,$key)
    从 map 中删除一个 key,返回一个新 map
    */
    $map:map-remove($social-colors,dribble);

    $map:(
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
    );

    /*
    map-keys(\$map)
    返回 map 中所有的 key
    */
    map-keys($social-colors); // "dribble","facebook","github","google","twitter"

    /*
    map-values(\$map)
    返回 map 中所有的 value
    */
    map-values($social-colors) // #ea4c89,#3b5998,#171515,#db4437,#55acee

    /*
    map-has-key(\$map,\$key)
    根据给定的 key 值判断 map 是否有对应的 value 值,如果有返回 true,否则返回 false
    */
    @function colors($color){
    @if not map-has-key($social-colors,$color){
    @warn "No color found for `#{$color}` in $social-colors map. Property omitted.";
    }
    @return map-get($social-colors,$color);
    }

    .btn-dribble {
    color: colors(dribble); // color: #ea4c89;
    }
    /*
    keywords($args)
    返回一个函数的参数,这个参数可以动态的设置 key 和 value
    */
    @mixin map($args...){
    $social-color: keywords($args);
    .btn-dribble{
    color: map-get($social-color,facebook); // color: #3b5998;
    }
    }

    @include map(
    $dribble: #ea4c89,
    $facebook: #3b5998,
    $github: #171515,
    $google: #db4437,
    $twitter: #55acee
    );
  • RGB()函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*
    rgba()
    将一个颜色根据透明度转换成rgba颜色
    */
    rgba($red,$green,$blue,$alpha) //将一个rgba颜色转译出来,和未转译的值一样
    rgba($color,$alpha) //将一个Hex颜色转换成rgba颜色

    /*
    red(),green()和blue()函数分别获取一个颜色之中的红色值,绿色值和蓝色值
    */
    red(#f36) // 255
    green(#f36) // 51
    blue(#f36) // 102

    /*
    mix()
    将两种颜色根据一定的比例混合在一起,生成另一种颜色
    */
    mix($color-1,$color-2,$weight); // $weight 为合并比重,默认值为 50%
  • HSL()函数

    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
    // hsl($hue,$saturation,$lightness)
    通过色相(hue)、饱和度(saturation)和亮度(lightness)的值创建一个颜色
    // hsla($hue,$saturation,$lightness,$alpha)
    通过色相(hue)、饱和度(saturation)、亮度(lightness)和透明(alpha)的值创建一个颜色
    // hue($color)
    从一个颜色中获取色相(hue)值
    // saturation($color)
    从一个颜色中获取饱和度(saturation)值
    // lightness($color)
    从一个颜色中获取亮度(lightness)值
    // adjust-hue($color,$degrees)
    通过改变一个颜色的色相值,创建一个新的颜色
    // lighten($color,$amount)
    通过改变颜色的亮度值,让颜色变亮,创建一个新的颜色
    // darken($color,$amount)
    通过改变颜色的亮度值,让颜色变暗,创建一个新的颜色
    // saturate($color,$amount)
    通过改变颜色的饱和度值,让颜色更饱和,从而创建一个新的颜色
    // desaturate($color,$amount)
    通过改变颜色的饱和度值,让颜色更少的饱和,从而创建出一个新的颜色
    // grayscale($color)
    将一个颜色变成灰色,相当于desaturate($color,100%)
    // complement($color)
    返回一个补充色,相当于adjust-hue($color,180deg)
    // invert($color)
    反回一个反相色,红、绿、蓝色值倒过来,而透明度不变
  • Opacity()函数

    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
    /*
    alpha()和opacity()函数主要用来获取一个颜色的透明度
    */
    alpha(red) // 1
    alpha(rgba(red, .8)) // 0.8
    opacity(red) // 1
    opacity(rgba(red, .8)) //0.8

    /*
    rgba()
    可以创建一个颜色,同时还可以对颜色修改其透明度。其可以接受两个参数,第一个参数为颜色,第二个参数是你需要设置的颜色透明值。
    */
    rgba(hsl(33,7%,21%),.5) // rgba(57, 54, 50, 0.5)

    /*
    opacity() fade-in()
    对已有颜色的透明度做一个加法运算,会让颜色更加不透明
    */
    opacify(hsla(22,34%,23%,.6),.15) // rgba(79, 53, 39, 0.75)

    /*
    transparentize() fade-out()
    对已有颜色的透明度做一个减法法运算,会让颜色更加透明
    */
    transparentize(rgba(98,233,124,.3),.11) // rgba(98, 233, 124, 0.19)

@规则

  • @import
    Sass 扩展了 CSS的 @import 规则,使其能够引入 scss 和 sass 文件,且引入的文件都会被合并并输出成一个单个的 css 文件,另外被导入的文件中所定义的变量或 mixins 都可以在主文件中使用

    在以下几种情况下,@import 规则会被编译成 CSS 的 @import 规则:

    • 如果文件扩展名是.css
    • 如果文件名是以 http:// 开头
    • 如果文件名是 url()
    • 如果 @import 包含了任何媒体查询 (media queries)

    没有上述情况且文件扩展名是 .scss 或 .sass,该名称的 sass 或 scss 文件就会被引入,如果没有扩展名,sass将找出具有 .scss 或 .sass 扩展名的同名文件并将其引入

    还可以通过一个 @import 引入多个文件,如:
    @import "rounded-corners", "text-shadow";

    如果你希望引入的 sass 或 scss文件不被编译成一个 css 文件,可以在文件名的前面加上一个下划线,这样就可以像往常一样引入这个文件,并且可以省略掉文件名前面的下划线(同一个目录下不能存在带下划线和不带下划线的同名文件)

    还可以把 @import 规则嵌套在 CSS 规则和 @media 规则中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // example.scss
    .example {
    color: red;
    }

    // demo.scss
    #main {
    //@import "example" // color: red;
    }
  • @media

    • 可以嵌套在 css 规则中,并且会冒泡到外面

      1
      2
      3
      4
      5
      6
      7
      // .scss
      .sidebar {
      width: 300px;
      @media screen and (orientation: landscape) {
      width: 500px;
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      // .css
      .sidebar {
      width: 300px;
      }
      @media screen and (orientation: landscape) {
      .sidebar {
      width: 500px;
      }
      }
    • 可以嵌套在 @media里

      1
      2
      3
      4
      5
      6
      7
      8
      // .scss
      @media screen {
      .sidebar {
      @media (orientation: landscape) {
      width: 500px;
      }
      }
      }
      1
      2
      3
      4
      5
      6
      // .css
      @media screen and (orientation: landscape) {
      .sidebar {
      width: 500px;
      }
      }
    • 还可以使用插值#{}

  • @extend
    sass 中的 @extend 是用来扩展选择器或占位符

    • 扩展单一选择器

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      // .scss
      #context a%extreme {
      color: blue;
      font-weight: bold;
      font-size: 2em;
      }

      .notice {
      @extend %extreme;
      }
      1
      2
      3
      4
      5
      6
      // .css
      #context a.notice {
      color: blue;
      font-weight: bold;
      font-size: 2em;
      }
  • @at-root

    • 跳出根元素

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      // .scss
      .a {
      color: red;
      .b {
      color: orange;
      .c {
      color: yellow;
      @at-root .d {
      color: green;
      }
      }
      }
      }
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      // .css
      .a {
      color: red;
      }

      .a .b {
      color: orange;
      }

      .a .b .c {
      color: yellow;
      }

      .d {
      color: green;
      }
  • @debug
    在 Sass 中是用来调试的,当你的在 Sass 的源码中使用了 @debug 指令之后,Sass 代码在编译出错时,在命令终端会输出你设置的提示 Bug

  • @warn
    和 @debug 功能类似,用来帮助我们更好的调试 Sass

  • @error
    和上述功能类似,帮助我们更好的调试 Sass,打印错误信息