前端CSS预处理器Sass

前面的话

  "CSS 预处理器"(css preprocessor) 的基本思想是,用一种专门的编程语言,进行网页样式设计,然后再编译成正常的 CSS 文件。SASS 是一种 CSS 的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得 CSS 的开发,变得简单和可维护。本文将详细介绍 sass 的使用

 

定义

  Sass 是一门高于 CSS 的元语言,它能用来清晰地、结构化地描述文件样式,有着比普通 CSS 更加强大的功能。
Sass 能够提供更简洁、更优雅的语法,同时提供多种功能来创建可维护和管理的样式表

【SASS 和 SCSS】

  Sass 和 SCSS 其实是同一种东西,我们平时都称之为 Sass,两者之间不同之处有以下两点:1、文件扩展名不同,Sass 是以“.sass”后缀为扩展名,而 SCSS 是以“.scss”后缀为扩展名;2、语法书写方式不同,Sass 是以严格的缩进式语法规则来书写,不带大括号 ({}) 和分号(😉,而 SCSS 的语法书写和我们的 CSS 语法书写方式非常类似

  下面为 Sass 语法

$font-stack: Helvetica, sans-serif  // 定义变量
$primary-color: #333 // 定义变量

body
font: 100% $font-stack
color: $primary-color

  下面为 SCSS 语法

$font-stack: Helvetica, sans-serif;
$primary-color: #333;

body {
font: 100% $font-stack;
color: $primary-color;
}

  编译出来的 CSS 为

body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

 

安装

  在 Windows 平台下安装 Ruby 需要先有 Ruby 安装包。Ruby 安装文件
下载好后,可以按应用软件安装步骤进行安装 Ruby

  在安装过程中选择第二个选项 (若不选中,就会出现编译时找不到 Ruby 环境的情况),如下图所示

#

  Ruby 安装完成后,在开始菜单中找到新安装的 Ruby,并启动 Ruby 的 Command 控制面板 (Start Command Prompt with Ruby)

  安装好 Ruby 之后,接下来就可以安装 Sass 了。打开电脑的命令终端,输入下面的命令:

gem install sass
#

【更新 Sass】

  在命令终端执行下列命令,可以将 sass 升级到最高版本

gem update sass

【卸载 Sass】

  在命令终端执行下列命令,可以卸载 sass

gem uninstall sass

 

编译

  Sass 的编译包括以下几种方法:命令编译、GUI 工具编译和自动化编译

  [注意]在编译 sass 时,常见的两个错误是字符编码错误 (不支持 gbk 编码) 和路径错误(不支持中文)

1、命令编译

  命令编译是指使用电脑中的命令终端,通过输入 Sass 指令来编译 Sass。这种编译方式是最直接也是最简单的一种方式

【单文件编译】

sass <要编译的Sass文件路径>/style.scss:<要输出CSS文件路径>/style.css

【多文件编译】

  下面的命令表示将项目中“sass”文件夹中所有“.scss”(“.sass”) 文件编译成“.css”文件,并且将这些 CSS 文件都放在项目中“css”文件夹中

sass sass/:css/

  在实际编译过程中,会发现上面的命令只能一次性编译。每次保存“.scss”文件之后,都得重新执行一次这样的命令。如此操作太麻烦,其实还有一种方法,就是在编译 Sass 时,开启“watch”功能,这样只要代码进行任何修改,都能自动监测到代码的变化,并且直接编译出来:

  [注意] 冒号的左右两侧一定不要留空格

sass --watch <要编译的Sass文件路径>/style.scss:<要输出CSS文件路径>/style.css

sass --watch sass/test.scss:css/test.css

#

调试

  使用 chrome 浏览器的 sourcemap 功能可以将本地的文件和服务器上的文件关联起来。这样,通过 chrome 的开发者工具调试网页 (如更改一个 css 属性值) 时,本地文件的内容也会相应地发生变化并保存。如果再使用 sass 的 watch 命令, 在调试 sass 文件时,就可以实时保存文件并通过浏览器看到效果

  如下图所示,点击 map to network resource,把本地文件关联到服务器上相应文件。浏览器会智能地把项目目录下的其他 css 文件和 html 文件和服务器上对应的文件都关联起来

#
#

编译风格

  SASS 提供四个编译风格的选项:

nested:嵌套缩进的css代码,它是默认值。
expanded:没有缩进的、扩展的css代码。
compact:简洁格式的css代码。
compressed:压缩后的css代码。

  生产环境当中,一般使用最后一个选项

sass --style compressed test.sass test.css

2、GUI 编译

  一般地,使用 koala 编译器来对 sass 进行编译

#

3、自动化编译

  使用 grunt 或 gulp 可以配置 sass 的编译

  下面以 grunt 为例,首先需要安装 sass 插件

npm install grunt-contrib-sass --save-dev

  然后,初始化 grunt 配置

grunt.initConfig({
  sass: {                              // Task 
    dist: {                            // Target 
      options: {                       // Target options 
        style: 'expanded'
      },
      files: {                         // Dictionary of files 
        'main.css': 'main.scss',       // 'destination': 'source' 
        'widgets.css': 'widgets.scss'
      }
    }
  }
});

  接下来,告诉 grunt 将使用该插件

grunt.loadNpmTasks('grunt-contrib-sass');

  最后,告诉 grunt 当我们在终端中输入 grunt 时需要做些什么

grunt.registerTask('default', ['sass']);

 

语法

数据类型

  SassScript 支持六种主要的数据类型:

  1、数字 (例如 1.2、13、10px)

  2、文本字符串,无论是否有引号 (例如 "foo"、'bar'、baz)

  3、颜色 (例如 blue、#04a3f9、rgba(255, 0, 0, 0.5))

  4、布尔值 (例如 true、false)

  5、空值 (例如 null)

  6、值列表,用空格或逗号分隔 (例如 1.5em 1em 0 2em、Helvetica, Arial, sans-serif)

  Sass 还支持所有其他 CSS 属性值类型,例如 Unicode 范围和!important 声明。然而,它不会对这些类型做特殊处理。它们只会被当做不带引号的字符串看待

 

注释

  sass 有两种注释方式,一种是标准的 css 注释方式 /* */,另一种则是 // 双斜杆形式的单行注释,不过这种单行注释不会输入到 CSS 中

/*
* 多行注释
*/
body{
  padding:5px;
} 

//单行注释
body{
padding:5px; //5px
}

 

变量

  SASS 的变量用法类似于 php 与 css 语法的结合,所有变量以 $ 变量,变量名和变量值之间用冒号隔开。定义之后可以在全局范围内使用

$blue : #1875e7; 
div {
  color : $blue;
}
#

  如果变量需要镶嵌在字符串之中,就必须需要写在 #{} 之中

$side : left;
.rounded {
  border-#{$side}-radius: 5px;
}

【默认变量】

  sass 的默认变量仅需要在值后面加上!default 即可。sass 的默认变量一般用来设置默认值,然后根据需求来覆盖。覆盖的方式也很简单,只需要在默认变量之前重新声明变量即可

//sass style
//-------------------------------
$baseLineHeight:        2;
$baseLineHeight:        1.5 !default;
body{
    line-height: $baseLineHeight; 
}

//css style
//-------------------------------
body{
line-height:2;
}

【特殊变量】

  一般我们定义的变量都为属性值,可直接使用,但是如果变量作为属性或在某些特殊情况下 (如嵌套在字符串中) 等则必须要以 #{$variables}形式使用

$borderDirection:       top !default; 
$baseFontSize:          12px !default;

// 应用于 class 和属性
.border-#{$borderDirection}{
border-#{$borderDirection}:1px solid #ccc;
}
// 应用于复杂的属性值
body{
font:#{$baseFontSize}/#{$baseLineHeight};
}

【全局及局部变量】

  在选择器、函数、混合宏... 的里面定义的变量叫局部变量,它们的外面定义的变量为全局变量

//scss
$color: orange;
.block {
  color: $color;// 调用全局变量
}
em {
  $color: red;// 定义局部变量
  a {
    color: $color;// 调用局部变量
  }
}
span {
  color: $color;// 调用全局变量
}

//CSS
.block {
color: orange;
}
em a {
color: red;
}
span {
color: orange;
}

 

嵌套

  选择器嵌套提供了一个通过局部选择器相互嵌套实现全局选择的方法,Sass 的嵌套分为两种:1、选择器嵌套;2、属性嵌套

【选择器嵌套】

  [注意] 在 sass 嵌套嵌套中,可以使用 & 表示父元素选择器

#top_nav{
  line-height: 40px;
  li{
    float:left;
  }
  a{
    display: block;
    padding: 0 10px;
    color: #fff;
&amp;<span class="hljs-selector-pseudo">:hover</span>{
  <span class="hljs-attribute">color</span>:<span class="hljs-number">#ddd</span>;
}

}
}

//css style
//-------------------------------
#top_nav{
line-height: 40px;
}
#top_nav li{
float:left;
}
#top_nav a{
display: block;
padding: 0 10px;
color: #fff;
}
#top_nav a:hover{
color:#ddd;
}

【属性嵌套】

  CSS 有一些属性前缀相同,只是后缀不一样,比如:border-top/border-right,与这个类似的还有 margin、padding、font 等

  [注意]border 后面必须有冒号

//css
.box {
    border-top: 1px solid red;
    border-bottom: 1px solid green;
}
//scss
.box {
  border: {
   top: 1px solid red;
   bottom: 1px solid green;
  }
}

 

混合宏

  混合宏是可以重用的代码块

  在 Sass 中,使用“@mixin”来声明一个混合宏

@mixin border-radius{
    -webkit-border-radius: 5px;
    border-radius: 5px;
}

  可以使用@include命令,来调用混合宏 mixin

button {
    @include border-radius;
}

  mixin 指定参数和缺省值

@mixin border-radius($radius:5px){
    -webkit-border-radius: $radius;
    border-radius: $radius;
}
div{
  @include border-radius(10px);
}

  Sass 中的混合宏还提供更为复杂的情况,可以在大括号里面带有逻辑关系

@mixin box-shadow($shadow...) {
  @if length($shadow) >= 1 {
    @include prefixer(box-shadow, $shadow);
  } @else{
    $shadow:0 0 4px rgba(0,0,0,.3);
    @include prefixer(box-shadow, $shadow);
  }
}

  Sass 在调用相同的混合宏时,并不能智能的将相同的样式代码块合并在一起。这也是 Sass 的混合宏最大的不足之处

【占位符】

  占位符是介于混合宏和变量之间的一个功能

//SCSS
%mt5 {
  margin-top: 5px;
}
%pt5{
  padding-top: 5px;
}

.block {
@extend %mt5;

span {
@extend %pt5;
}
}

//CSS
.block {
margin-top: 5px;
}

.block span {
padding-top: 5px;
}

 

继承

  SASS 允许一个选择器,继承另一个选择器。比如,现有 class1

  .class1{
      border: 1px solid black;
  }

  class2 要继承 class1,就要使用@extend命令

.class2{
  @extend .class1;
  font-size:120%;
}

  Sass 中的继承,可以继承类样式块中所有样式代码,而且编译出来的 CSS 会将选择器合并在一起,形成组合选择器

//SCSS
.btn {
  border: 1px solid #ccc;
  padding: 6px 10px;
  font-size: 14px;
}
.btn-primary {
  background-color: #f36;
  @extend .btn;
}
.btn-second {
  background-color: orange;
  @extend .btn;
}
//CSS
.btn, .btn-primary, .btn-second {
  border: 1px solid #ccc;
  padding: 6px 10px;
  font-size: 14px;
}
.btn-primary {
  background-color: #f36;
}
.btn-second {
  background-clor: orange;
}

 

运算

  SASS 允许在代码中使用算式

【注意事项】

  1、100px * 2px 会报错,乘法应该写成 100px * 2

  2、因为除号 / 在 CSS 中在特殊的含义,所以为了避免除法不生效,需要在外面添加一个小括号

  3、类似于 javascript,sass 中的加法也有字符串连接的作用

$num: '1' + '1';   
body{
  top: 10px + 10px;//20
  left: 10px - 10px;//0
  right: 100px *2;//200
  bottom: (100px/2);//50
  width: $num;//11
}

 

语句

【条件语句】

  @if指令是一个 SassScript,它可以根据条件来处理样式块,如果条件为 true 返回一个样式块,反之 false 返回另一个样式块。在 Sass 中除了@if,还可以配合@else if@else一起使用

//scss
@mixin blockOrHidden($boolean:true) {
  @if $boolean {
      display: block;
    }
  @else {
      display: none;
    }
}
.block {
  @include blockOrHidden;
}

.hidden{
@include blockOrHidden(false);
}

//CSS:
.block {
display: block;
}
.hidden {
display: none;
}

【循环语句】

for 循环

  Sass 中的 for 循环有两种方式

@for $i from <start> through <end>
@for $i from <start> to <end>

这两个的区别是关键字 through 表示包括 end,而 to 则不包括 end

//scss
@for $i from 1 through 3 {
  .item-#{$i} { width: 2em * $i; }
}
//css
.item-1 {
  width: 2em;
}
.item-2 {
  width: 4em;
}
.item-3 {
  width: 6em;
}

while 循环

//SCSS
$types: 4;
$type-width: 20px;
@while $types > 0 {
    .while-#{$types} {
        width: $type-width + $types;
    }
    $types: $types - 1;
}

//css
.while-4 {
width: 24px;
}

.while-3 {
width: 23px;
}

.while-2 {
width: 22px;
}

.while-1 {
width: 21px;
}

each 循环

//scss
$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;
}

//css
.author-bio .photo-adam {
background: url("/images/avatars/adam.png") no-repeat; }
.author-bio .photo-john {
background: url("/images/avatars/john.png") no-repeat; }
.author-bio .photo-wynn {
background: url("/images/avatars/wynn.png") no-repeat; }
.author-bio .photo-mason {
background: url("/images/avatars/mason.png") no-repeat; }
.author-bio .photo-kuroir {
background: url("/images/avatars/kuroir.png") no-repeat; }

 

函数

  在命令终端开启 sass -i 这个命令,相当于开启 Sass 的函数计算

sass -i

【字符串函数】

  unquote($string):删除字符串中的引号

//SCSS
.test1 {
    content:  unquote('Hello Sass!') ;
}
.test3 {
    content: unquote("I'm Web Designer");
}
.test5 {
    content: unquote('"Hello Sass!"');
}
//css
.test1 {
  content: Hello Sass!; }
.test3 {
  content: I'm Web Designer; }
.test5 {
  content: "Hello Sass!"; }

  quote($string):给字符串添加引号,如果字符串自身带有引号会统一换成双引号 ""

//SCSS
.test1 {
    content:  quote('Hello Sass!');
}
.test2 {
    content: quote("Hello Sass!");
}
.test3 {
    content: quote(ImWebDesigner);
}
.test4 {
    content: quote(' ');
}
//CSS
.test1 {
  content: "Hello Sass!";
}
.test2 {
  content: "Hello Sass!";
}
.test3 {
  content: "ImWebDesigner";
}
.test4 {
  content: "";
}

  To-upper-case():将字符串小写字母转换成大写字母

//SCSS
.test {
  text: to-upper-case(aaaaa);
  text: to-upper-case(aA-aAAA-aaa);
}
//CSS
.test {
  text: AAAAA;
  text: AA-AAAA-AAA;
} 

  To-lower-case():将字符串转换成小写字母

//SCSS
.test {
  text: to-lower-case(AAAAA);
  text: to-lower-case(aA-aAAA-aaa);
}
//CSS
.test {
  text: aaaaa;
  text: aa-aaaa-aaa;
} 

【数字函数】

  percentage($value):将一个不带单位的数转换成百分比值

//scss
.footer{
    width : percentage(.2)
}
//css
.footer{
    width : 20%
}

  round()将一个数四舍五入为一个最接近的整数

//scss
.footer1 {
   width:round(15.8px)
}
.footer2 {
   width:round(3.4em)
}
//css
.footer1 {
   width:16px
}
.footer2 {
   width:3em
}

  ceil()向上取整

//scss
.footer1 {
   width:ceil(15.8px)
}
.footer2 {
   width:ceil(3.4em)
}
//css
.footer1 {
   width:16px
}
.footer2 {
   width:4em
}

  floor()向下取整

//scss
.footer1 {
   width:floor(15.8px)
}
.footer2 {
   width:floor(3.4em)
}
//css
.footer1 {
   width:15px
}
.footer2 {
   width:3em
}

  abs()取绝对值

//scss
.footer1 {
   width:abs(-15.8px)
}
.footer2 {
   width:abs(3.4em)
}
//css
.footer1 {
   width:15.7px
}
.footer2 {
   width:3.4em
}

  min()取最小值,max()取最大值

  [注意]min()和 max() 都只可以比较相同单位的数值,否则会报错

//scss
div{
    height:max(10px,23px);
    width:min(10px,23px);
}
//css
div{
  height:23px;
  width:10px;
}

  random()用来获取一个随机数

//scss
div{
    color: rgba(200, 150, 40, random());
}
//css
div {
  color: rgba(200, 150, 40, 0.57236);
}

【列表函数】

  length()用来返回一个列表中有几个值。length() 函数中的列表参数之间使用空格隔开,不能使用逗号,否则函数将会出错

>> length(10px)
1
>> length(10px 20px (border 1px solid) 2em)
4
>> length(border 1px solid)
3

  nth($list,$n)用来指定列表中某个位置的值,nth() 函数的起始值为 1

>> nth(10px 20px 30px,1)
10px
>> nth((Helvetica,Arial,sans-serif),2)
"Arial"
>> nth((1px solid red) border-top green,1)
(1px "solid" #ff0000)

  join()用来将两个列表连接合并成一个列表。不过 join() 只能将两个列表连接成一个列表,如果直接连接两个以上的列表将会报错

>> join(10px 20px, 30px 40px)
(10px 20px 30px 40px)
>> join((blue,red),(#abc,#def))
(#0000ff, #ff0000, #aabbcc, #ddeeff)
>> join((blue,red),(#abc #def))
(#0000ff, #ff0000, #aabbcc, #ddeeff)

  append()用来将某个值插入到列表中,并且处于最末位

>> append(10px 20px ,30px)
(10px 20px 30px)
>> append((10px,20px),30px)
(10px, 20px, 30px)
>> append(green,red)
(#008000 #ff0000)
>> append(red,(green,blue))
(#ff0000 (#008000, #0000ff))

  zip()用于将多个列表值转成一个多维的列表。在使用 zip() 函数时,每个单一的列表个数值必须是相同的,否则将会出错

>> zip(1px 2px 3px,solid dashed dotted,green blue red)
((1px "solid" #008000), (2px "dashed" #0000ff), (3px "dotted" #ff0000)) 

  index()类似于索引一样,用来找出某个值在列表中所处的位置。起始值是 1,不是 0

>> index(1px solid red, 1px)
1
>> index(1px solid red, solid)
2
>> index(1px solid red, red)
3 

  type-of()主要用来判断一个值是属于什么类型

  number 为数值型,string 为字符串型,bool 为布尔型,color 为颜色型

>> type-of(100)
"number"
>> type-of(100px)
"number"
>> type-of("asdf")
"string"
>> type-of(asdf)
"string"
>> type-of(true)
"bool"
>> type-of(false)
"bool"
>> type-of(#fff)
"color"
>> type-of(blue)
"color"
>> type-of(1 / 2 = 1)
"string"

  unit()用来获取一个值所使用的单位,碰到复杂的计算时,其能根据运算得到一个“多单位组合”的值,不过只允许乘、除运算

>> unit(100)
""
>> unit(100px)
"px"
>> unit(20%)
"%"
>> unit(1em)
"em"
>> unit(10px * 3em)
"em*px"
>> unit(10px / 3em)
"px/em"
>> unit(10px * 2em / 3cm / 1rem)
"em/rem"

  unitless()用来判断一个值是否带有单位,如果不带单位返回的值为 true,带单位返回的值为 false

>> unitless(100)
true
>> unitless(100px)
false
>> unitless(100em)
false
>> unitless(100%)
false
>> unitless(1 /2 )
true
>> unitless(1 /2 + 2 )
true
>> unitless(1px /2 + 2 )
false

  comparable()用来判断两个数是否可以进行“加,减”以及“合并”。如果可以返回值为 true,如果不可以返回值是 false

>> comparable(2px,1%)
false
>> comparable(2px,1em)
false
>> comparable(2rem,1em)
false
>> comparable(2px,1cm)
true
>> comparable(2px,1mm)
true  

  Miscellaneous()称为三元条件函数。该函数有两个值,当条件成立返回一种值,当条件不成立时返回另一种值

if($condition,$if-true,$if-false) 

>> if(true,1px,2px)
1px
>> if(false,1px,2px)
2px

【颜色函数】

RGB 颜色函数

  rgb($red,$green,$blue)根据红、绿、蓝三个值创建一个颜色

  rgba($red,$green,$blue,$alpha)根据红、绿、蓝和透明度值创建一个颜色

  除了与 CSS 相同的 rgba()格式外,sass 中的 rgba() 还支持 rgba(\(color,\)alpha) 的格式。在实际工作中,如果在已知颜色的情况下,不改变颜色只加透明度,这个函数就能起到效果了

.overlayout{
  background-color:rgba(#773,0.5);
}

  red($color)从一个颜色中获取其中红色值

  green($color)从一个颜色中获取其中绿色值

  blue($color)从一个颜色中获取其中蓝色值

  mix($color-1,$color-2,[$weight])把两种颜色混合在一起。$color-1$color-2指需要合并的颜色,颜色可以是任何表达式,也可以是颜色变量

  $weight为第一个颜色合并所占的比例 (权重),默认值为 50%,其取值范围是 0~1 之间。它是由每个 RGB 的百分比来衡量的,当然透明度也会有一定的权重。默认的比例是 50%,这意味着两个颜色各占一半,如果指定的比例是 25%,这意味着第一个颜色所占比例为 25%,第二个颜色所占比例为 75%

mix(#f00, #00f) => #7f007f
mix(#f00, #00f, 25%) => #3f00bf
mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
#

HSL 颜色函数

  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)通过改变一个颜色的色相值,创建一个新的颜色。色相是色彩的首要特征,是区别各种不同色彩的最准确的标准。事实上任何黑白灰以外的颜色都有色相的属性,而色相也就是由原色、间色和复色来构成的

  darken($color,$amount)通过改变颜色的亮度值,让颜色变暗,创建一个新的颜色

  lighten($color,$amount)通过改变颜色的亮度值,让颜色变亮,创建一个新的颜色

  lighten()和 darken() 两个函数都是围绕颜色的亮度值做调整的,其中 lighten()函数会让颜色变得更亮,与之相反的 darken() 函数会让颜色变得更暗。这个亮度值可以是 01 之间,不过常用的一般都在 3%20% 之间

  [注意] 当颜色亮度值接近或大于 100%,颜色会变成白色;反之颜色亮度值接近或小于 0 时,颜色会变成黑色

//SCSS
$baseColor: #ad141e;
.lighten {
    background: lighten($baseColor,10%);
}
.darken{
    background: darken($baseColor,10%);
}
//CSS
.lighten {
  background: #db1926;
}
.darken {
  background: #7f0f16;
}
#

  saturate($color,$amount)通过改变颜色的饱和度值,让颜色更饱和,从而创建一个新的颜色。饱和度是指色彩的鲜艳程度,也称色彩的纯度

  desaturate($color,$amount)通过改变颜色的饱和度值,让颜色更少的饱和,从而创建出一个新的颜色

  saturate()、desaturate() 这两个函数是通过改变颜色的饱和度来得到一个新的颜色,他们和前面介绍的修改亮度得到新颜色的方法非常相似

#

  grayscale($color)函数会颜色的饱和度值直接调至 0%,所以此函数与 desaturate($color,100%) 所起的功能是一样的。一般这个函数能将彩色颜色转换成不同程度的灰色将一个颜色变成灰色

//SCSS
$baseColor: #ad141e;
.grayscale {
  background: grayscale($baseColor);
}
.desaturate {
  background: desaturate($baseColor,100%);
}
//CSS
.grayscale {
  background: #616161;
}
.desaturate {
  background: #616161;
}

  complement($color)返回一个补充色,相当于 adjust-hue($color,180deg)

  invert($color)返回一个反相色,红、绿、蓝色值倒过来,而透明度不变

>> hsl(200,30%,60%) // 通过 h200,s30%,l60% 创建一个颜色
#7aa3b8

>> hsla(200,30%,60%,.8)// 通过 h200,s30%,l60%,a80% 创建一个颜色
rgba(122, 163, 184, 0.8)

>> hue(#7ab)// 得到 #7ab 颜色的色相值
195deg

>> saturation(#7ab)// 得到 #7ab 颜色的饱和度值
33.33333%

>> lightness(#7ab)// 得到 #7ab 颜色的亮度值
60%

>> adjust-hue(#f36,150deg) // 改变 #f36 颜色的色相值为 150deg
#33ff66

>> lighten(#f36,50%) // 把 #f36 颜色亮度提高 50%
#ffffff

>> darken(#f36,50%) // 把 #f36 颜色亮度降低 50%
#33000d

>> saturate(#f36,50%) // 把 #f36 颜色饱和度提高 50%
#ff3366

>> desaturate(#f36,50%) // 把 #f36 颜色饱和度降低 50%
#cc667f

>> grayscale(#f36) // 把 #f36 颜色变成灰色
#999999

>> complement(#f36)
#33ffcc

透明度颜色函数

  在 CSS 中除了可以使用 rgba、hsla 和 transform 来控制颜色透明度之外,还可以使用 opacity 来控制,只不过前两者只是针对颜色上的透明通道做处理,而后者是控制整个元素的透明度

  alphpa()opacity()很简单,与前面介绍的 red()、green() 等函数很类似。函数的主要功能是用来获取一个颜色的透明度值。如果颜色没有特别指定透明度,那么这两个函数得到的值都会是 1

>> alpha(red)
1
>> alpha(rgba(red,.8))
0.8
>> opacity(red)
1
>> opacity(rgba(red,.8))
0.8

  opacify()fade-in()是用来对已有颜色的透明度做一个加法运算,会让颜色更加不透明。其接受两个参数,第一个参数是原始颜色,第二个参数是需要增加的透明度值,其取值范围主要是在 0~1 之间。当透明度值增加到大于 1 时,会以 1 计算,表示颜色不具有任何透明度

>> opacify(rgba(22,34,235,.6),.2)
rgba(22, 34, 235, 0.8)
>> opacify(rgba(22,34,235,.6),.5)
#1622eb
>> opacify(hsla(22,34%,23%,.6),.15)
rgba(79, 53, 39, 0.75)
>> opacify(hsla(22,34%,23%,.6),.415)
#4f3527
>> opacify(red,.15)
#ff0000
>> opacify(#89adde,.15)
#89adde
>> fade-in(rgba(23,34,34,.5),.15)
rgba(23, 34, 34, 0.65)
>> fade-in(rgba(23,34,34,.5),.615)
#172222

  transparentize()fade-out()所起作用刚好与 opacify()和 fade-in() 函数相反,让颜色更加的透明。这两个函数会让透明值做减法运算,当计算出来的结果小于 0 时会以 0 计算,表示全透明

>> transparentize(red,.5)
rgba(255, 0, 0, 0.5)
>> transparentize(#fde,.9)
rgba(255, 221, 238, 0.1)
>> transparentize(rgba(98,233,124,.3),.11)
rgba(98, 233, 124, 0.19)
>> transparentize(rgba(98,233,124,.3),.51)
rgba(98, 233, 124, 0)
>> fade-out(red,.9)
rgba(255, 0, 0, 0.1)
>> fade-out(hsla(98,6%,23%,.5),.1)
rgba(58, 62, 55, 0.4)
>> fade-out(hsla(98,6%,23%,.5),.6)
rgba(58, 62, 55, 0)

 

数组

  Sass 的 map 常常被称为数据地图,也有人称其为数组,因为它总是以 key:value 成对的出现,但其更像是一个 JSON 数据

$map: (
    key1: value1,
    key2: value2,
    key3: value3
)

  首先有一个类似于 Sass 的变量一样,用个 $ 加上命名空间来声明 map。后面紧接是一个小括号 (),将数据以 key:value 的形式赋予,其中 key 和 value 是成对出现,并且每对之间使用逗号(,) 分隔,其中最后一组后面没有逗号。其中键 key 是用来查找相关联的值 value。使用 map 可以很容易收集键的值和动态插入

  在 Sass 中常用下面的方式定义变量

$default-color: #fff !default;
$primary-color: #22ae39 !default;

  使用 map 可以更好的进行管理

$color: (
    default: #fff,
    primary: #22ae39
);    

  如果哪天需要新增加颜色变量值,在 map 中可以非常方便的添加

$color: (
    default: #fff,
    primary: #22ae39,
    negative: #d9534f
);

  对于 map,还可以让 map 嵌套 map。其实就是 map 的某一个 key 当成 map,里面可以继续放一对或者多对 key:value

$map: (
    key1: value1,
    key2: (
        key-1: value-1,
        key-2: value-2,
    ),
    key3: value3
);

  map 嵌套的实用性强,在换肤项目中,每一套皮肤对应的颜色蛮多的,使用 map 嵌套来管理颜色的变量就非常的有条理性,便于维护与管理

$theme-color: (
    default: (
        bgcolor: #fff,
        text-color: #444,
        link-color: #39f
    ),
    primary:(
        bgcolor: #000,
        text-color:#fff,
        link-color: #93f
    ),
    negative: (
        bgcolor: #f36,
        text-color: #fefefe,
        link-color: #d4e
    )
);

  为了方便的操作 map,在 Sass 中 map 自身带了七个函数

  map-get($map,$key)用来根据$key参数,返回$key$map中对应的 value 值。如果$key不存在$map中,将返回 null 值。该函数包含两个参数:$map表示定义好的 map;$key表示需要遍历的 key

//scss 
$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);
.btn-dribble{
  color: map-get($social-colors,facebook);
}
//css
.btn-dribble {
  color: #3b5998;
}

  如果是多重数组,可以嵌套使用map-get()函数来获取值

//scss
$theme-color: (
    default: (
        bgcolor: #fff,
        text-color: #444,
        link-color: #39f
    ),
    primary:(
        bgcolor: #000,
        text-color:#fff,
        link-color: #93f
    ),
    negative: (
        bgcolor: #f36,
        text-color: #fefefe,
        link-color: #d4e
    )
);
h1{
  color:map-get(map-get($theme-color,default),text-color);   
}
//css
h1 {
  color: #444;
}

  map-has-key($map,$key)用来判断 map 中是否存在参数中的 key,如果存在则返回 true,否则返回 false

//scss
$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);
@if map-has-key($social-colors,facebook){
    .btn-facebook {
        color: map-get($social-colors,facebook);
    }
} @else {
    @warn "No color found for faceboo in $social-colors map. Property ommitted."
}
//css
.btn-fackbook{
    color: #3b5998;
}   

  如果使用上面的写法,每获取一个 key 都需要写一个 if 语句,其实可以自定义函数来解决这个问题

//scss
$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);
@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);
}
.btn-facebook {
    color: colors(facebook);
}
.btn-github {
    color: colors(github);
}
.btn-google {
    color: colors(google);
}
.btn-twitter {
    color: colors(twitter);
}
.btn-weibo {
    color: colors(weibo);
}
//css
.btn-dribble {
  color: #ea4c89;
}
.btn-facebook {
  color: #3b5998;
}
.btn-github {
  color: #171515;
}
.btn-google {
  color: #db4437;
}
.btn-twitter {
  color: #55acee;
}

  用 each() 循环来减少重复

  @each $social-network,$social-color in $social-colors {
    .btn-#{$social-network} {
        color: colors($social-network);
    }
}

  map-keys($map)将返回$map中的所有 key。这些值赋予给一个变量,就是一个列表

//scss
$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);

@each $i in map-keys($social-colors){
.c-#{$i}{
color: map-get($social-colors,$i);
}
};
//css
.c-dribble {
color: #ea4c89;
}
.c-facebook {
color: #3b5998;
}
.c-github {
color: #171515;
}
.c-google {
color: #db4437;
}
.c-twitter {
color: #55acee;
}

  map-values($map)类似于map-keys($map)功能,不同的是,map-values($map)得到的是键值,而map-keys($map)得到的是键名

//scss
$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);

@each $val in map-values($social-colors){
.c-#{$val}{
color: $val;
}
};
//css
.c-dribble {
color: #ea4c89;
}
.c-facebook {
color: #3b5998;
}
.c-github {
color: #171515;
}
.c-google {
color: #db4437;
}
.c-twitter {
color: #55acee;
}

  map-merge($map1,$map2)用于将$map1$map2合并,然后得到一个新的$map。如果$map1$map2中有相同的$key名,那么将$map2中的$key会取代$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 中删除另一个 map,仅能通过删除 map 中的某个 key 得到新 map。如果删除的 key 并不存在于 map 中,那么map-remove()函数返回的新 map 和以前的 map 一样

$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);
$map:map-remove($social-colors,dribble);
$map:(
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);

  keywords($args)是一个动态创建 map 的函数。可以通过混合宏或函数的参数变创建 map。参数也是成对出现,其中$args变成 key( 会自动去掉$符号 ),而$args对应的值就是 value

@mixin map($args...){
    @debug keywords($args);
}
@include map(
  $dribble: #ea4c89,
  $facebook: #3b5998,
  $github: #171515,
  $google: #db4437,
  $twitter: #55acee
);
在命令终端可以看到一个@debug信息:
 DEBUG: (dribble: #ea4c89, facebook: #3b5998, github: #171515, google: #db4437, twitter: #55acee)

 

指令

  Sass 支持所有 CSS3 的@规则,以及一些 Sass 专属的规则,也被称为“指令 (directives)”

【@import】

  Sass 扩展了 CSS 的@import规则,让它能够引入 SCSS 和 Sass 文件。所有引入的 SCSS 和 Sass 文件都会被合并并输出一个单一的 CSS 文件。另外,被导入的文件中所定义的变量或 mixins 都可以在主文件中使用

  Sass 会在当前目录下寻找其他 Sass 文件,如果是 Rack、Rails 或 Merb 环境中则是 Sass 文件目录。也可以通过:load_paths 选项或者在命令行中使用 --load-path 选项来指定额外的搜索目录

  @import根据文件名引入。默认情况下,它会寻找 Sass 文件并直接引入,但是,在少数几种情况下,它会被编译成 CSS 的@import规则,包括以下几种情况:如果文件的扩展名是.css;如果文件名以 http:// 开头;如果文件名是 url();如果@import包含了任何媒体查询 (mediaqueries)

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

【@media】

  Sass 中的@media指令和 CSS 的使用规则一样的简单,但它有另外一个功能,可以嵌套在 CSS 规则中。有点类似 JS 的冒泡功能一样,如果在样式中使用@media指令,它将冒泡到外面

//scss
.sidebar {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}
//css
.sidebar {
  width: 300px; }
  @media screen and (orientation: landscape) {
    .sidebar {
      width: 500px; } }

【@extend】

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

//scss
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.error.intrusion {
  background-image: url("/image/hacked.png");
}
.seriousError {
  @extend .error;
  border-width: 3px;
}
//css
.error, .seriousError {
  border: 1px #f00;
  background-color: #fdd; }

.error.intrusion, .seriousError.intrusion {
background-image: url("/image/hacked.png");}

.seriousError {
border-width: 3px; }

【@at-root】

  @at-root从字面上解释就是跳出根元素。当选择器嵌套多层之后,想让某个选择器跳出,此时就可以使用@at-root

//scss
.a {
  color: red;
  .b {
    color: orange;
    .c {
      color: yellow;
      @at-root .d {
        color: green;
      }
    }
  }  
}
//css
.a {
  color: red;
}
.a .b {
  color: orange;
}
.a .b .c {
  color: yellow;
}
.d {
  color: green;
}     

【@debug】

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

@debug 10em + 12em;
会输出:
Line 1 DEBUG: 22em  

【@error、@warn】

  @error@warn@debug功能类似,可类比于 javascript 中的 console.error()、console.warn() 和 console.debug()

 

实例

  下面来使用 SCSS 来实现一个七色卡片的效果,如下图所示

#

  首先,要了解颜色模式除了 RGB 模式,还有 HSL 模式

  h: 色调 (hue) 可以为任意整数。0(或 360 或 -360)表示红色,60 表示黄色,120 表示绿色,180 表示青色,240 表示蓝色,300 表示洋红(当 h 值大于 360 时,实际的值等于该值模 360 后的值)

  s: 饱和度 (saturation),就是指颜色的深浅度和鲜艳程度。取 0-100% 范围的值,其中 0 表示灰度 (没有该颜色),100% 表示饱和度最高 (颜色最鲜艳)

  l: 亮度 (lightness),取 0-100% 范围的值,其中 0 表示最暗 (黑色),100% 表示最亮 (白色)

  [注意] 关于 CSS 中 HSL 模式的详细信息移步至此

  由于对色彩知识并没有深入的了解,就以图片表观上从左到右亮度逐渐变小为依据,来写 CSS

  下面来分析图片,从上到下分别是红、橙、黄、蓝、绿、紫、黑七种颜色,共 7 行。每行都有 21 列,从左到右,亮度逐渐变小。最左列为纯白,最右列为纯黑。所以,可以以最中心列的颜色为起点,向左 10 列,每列亮度增加 10%,最左列亮度为 100%。向右 10 列,每列亮度减小 10%,最右列亮度为 0%

  使用量图工具,量得每一行中心列的颜色值从上到下分别为:#e02744、#ec8a00、#fae200、#91de00、#47c9f2、#a500fe、#848484

  下面要使用 SASS 中关于亮度改变的函数:darken()让颜色变暗和 lighten() 让颜色变亮

  在 lighten()函数中,参数 amount 为 50%,则为全白。所以,第 1 到第 10 列的参数 amount 为从 50% 到 5%;类似地,在 darken() 函数中,参数 amount 为 50%,则为全黑。所以,第 12 到第 21 列的参数 amount 为从 5% 到 50%

【HTML 代码】

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="css/test.css">
</head>
<body>
<div class="box">
  <ul class="red">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul>
  <ul class="orange">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul>
  <ul class="yellow">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul>
  <ul class="green">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul>   
  <ul class="blue">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul> 
  <ul class="purple">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul>
  <ul class="grey">
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
  </ul>     
</div>
</body>
</html>

【SASS 代码】

body{margin: 0}
ul{margin: 0;padding: 0;list-style:none;overflow: hidden}
li{float:left;height: 30px;width: 20px;}
// 定义 colorMap 用于储存每一行中间列的颜色值
$colorMap: (
  red: #e02744,
  orange: #ec8a00,
  yellow: #fae200,
  green: #91de00,
  blue: #47c9f2,
  purple: #a500fe,
  grey: #848484
);
// 为一行中的每个元素设置背景颜色
@mixin changelightness($color){
  @for $index from 1 through 21 {
    // 从第一列到第十列,亮度增大值由 50% 变化到 5%
    @if($index < 11){
      //amount 表示当前列的亮度
      $amount: percentage((11-$index)/20);
      li:nth-child(#{$index}) {
        background-color: lighten($color,$amount);
      }
    }
    // 第十一列为中心列,以测量值赋值
    @if($index == 11){    
      li:nth-child(#{$index}){
          background-color: $color;
      }
    }  
    // 从第十二列到第二十一列,亮度减小值由 5% 变化到 50%
    @if($index > 11){ 
        $amount: percentage(($index - 11)/20);
        li:nth-child(#{$index}){
          background-color: darken($color,$amount);
        }
    }  
  }
}
// 通过 forEach 循环为每一行 (也就是 HTML 结构中的每一个 ul) 添加样式
@each $index in map-keys($colorMap){
  .#{$index}{
    @include changelightness(map-get($colorMap,$index));
  }
}

【实际效果】