一起学习

Table of Contents

TOC

本文的内容主要来自于 Sass 的文档,但并不是对其进行直接翻译,根据自己的理解对其进行了一些增减和修改。同时通过对比式的排版,也更容易看清楚 SassCSS 之间的转换。

如果你发现有错误或者有其他建议可以到GitHub上告诉我,或者提交PR。

#基本概念

通过下图可以了解 CSS 语法中的一些名词。本文提及这些名词时,也会直接用其英文名称。

css-syntax

#Sass 是什么

Sass 是 Syntactically Awesome StyleSheets 的缩写,它在原生 CSS 语法的基础上,提供了很多额外的功能,比如变量规则嵌套mixin 等等,并且完全兼容 CSS 的原有语法。Sass 的存在,让写 CSS 变的简单和有趣。

Sass 有两种语法。一种是 SCSS(Sassy CSS),它是对CSS 原有语法的扩展,也就是说一个 CSS 文件,也是一个有效的 SCSS 文件。使用这种语法的文件通常使用.scss作为扩展名。本文主要以 SCSS 为主。

还有一种是 缩进式语法(直接叫Sass),其语法简洁,使用代码的缩进,代替大括号,来表示 CSS selector 的层级嵌套关系。每条规则后的分号,也被省略去。使用这种语法的文件通常使用.sass作为扩展名。

#使用 Sass

#使用 Gulp 插件

这里是一个使用 gulp-sass 插件的例子。

var gulp = require('gulp'),
    sass = require('gulp-sass');

gulp.task('sass', () => {
  gulp.src('*.scss')
    .pipe(sass({
      outputStyle: 'expanded'
    })).on('error', sass.logError)
    .pipe(gulp.dest('dist'));
});

gulp.task('default', ['sass']);

#基本语法

#规则嵌套(Nested Rules)

Sass 允许 CSS 规则进行嵌套。这可能是 Sass 最常用的功能了。

scss
#main p {
  color: #f3f3f3;

  .redbox {
    background-color: #ff0000;
  }
}
css
#main p {
  color: #f3f3f3;
}

#main p .redbox {
  background-color: #ff0000;
}

这样在写规则的时候就不用每次都要重复写父级 selector,这使得包含很多层嵌套的复杂 CSS layout 变的简单。比如:

scss
#main {
  width: 97%;

  p, div {
    font-size: 2em;
    a { font-weight: bold; }
  }

  pre { font-size: 3em; }
}
css
#main {
  width: 97%;
}

#main p, #main div {
  font-size: 2em;
}

#main p a, #main div a {
  font-weight: bold;
}

#main pre {
  font-size: 3em;
}

在 selector 内部,可以使用 & 符号来引用 父级 selector。比如:

scss
.awesome-link {
  color: blue;
  &:hover {
    color: red;
  }
}

.post {
  font-size: 1em;
  &-head {
    font-size: 1.8em;
  }
}
css
.awesome-link {
  color: blue;
}

.awesome-link:hover {
  color: red;
}

.post {
  font-size: 1em;
}

.post-head {
  font-size: 1.8em;
}

#CSS 属性嵌套(Nested Properties)

CSS 中有一些属性存在于「命名空间」中,比如font-family, font-size, font-weight 都存在于 font 这个命名空间中。对于类似这样的属性,Sass 提供了一种快捷写法。注意下面例子中font后面的冒号:

scss
/*
 * Nested Properties
 */

.funky {
  font: {
    family: Monaco;
    size: 0.9em;
    weight: bold;
  }
}
css
/*
 * Nested Properties
 */
.funky {
  font-family: Monaco;
  font-size: 0.9em;
  font-weight: bold;
}

#代码注释

Sass 支持标准 CSS 中的多行注释,另外也支持 单行注释。

注意,在默认情况下生成的 CSS 中,多行注释会被保留,单行注释会被去除。

scss
/*
 * 这是一个多行注释
 * 会被保留在生成的 CSS 中
 */
body {
  color: black;
}

// 这是一个单行注释
// 会被移除
a {
  color: green;
}
css
/*
 * 这是一个多行注释
 * 会被保留在生成的 CSS 中
 */
body {
  color: black;
}

a {
  color: green;
}

#变量

Sass 中可以使用变量。定义变量就像写 CSS 规则一样,只是前面要加上美元符号($)。使用变量的时候,也是在变量名前面加上 $

仔细对比下面的 Sass 及其 CSS 输出。

scss
$width: 5em;

#main {
  width: $width;
}
css
#main {
  width: 5em;
}

#作用域

Sass 变量也是有作用域的。比如:

scss
.s1 {
  $width: 800px;
  width: $width;
}

.s2 {
  $width: 5em;
  width: $width;
}
css
.s1 {
  width: 800px;
}

.s2 {
  width: 5em;
}

#数据类型

Sass 支持7种数据类型:

通常,Sass 转换成 CSS 的时候,字符串会保留原来的样子,即如果在 Sass 有引号,则生成的 CSS 中也会有引号,Sass 中没有引号,则 CSS 中也不会有引号。

TODO interpolation

#列表(List)

在下面例子中,10px 15px 0 0Helvetica, Arial, sans-serif 就是一个 Sass 列表。Sass 列表由空格或逗号隔开。

.demo {
  margin: 10px 15px 0 0;
  font-face: Helvetica, Arial, sans-serif;
}

通常使用 Sass 列表函数来操作列表。比如说我们可以用 nth()函数来获取列表中得指定序号的值:

scss
$margin: 10px 20px 30px 10px;

.list-func-demo {
  margin-bottom: nth($margin, 3);
}
css
.list-func-demo {
  margin-bottom: 30px;
}

列表中除了可以包含简单的数字或字符串外,也可以包含其他列表。比如 1px 2px, 5px 6px 就是一个包含2个元素的列表,这2个元素又分别是列表 1px 2px 和列表 5px 6px

假设内外列表都是用的时空格或逗号时,可以使用小括号来区分开,比如 (1px 2px) (5px 6px)

需要了解的是,CSS 中并没有使用小括号区分列表的语法。所以 (1px 2px) (5px 6px) 装换成 CSS 的时候,会变成 1px 2px 5px 6px

#键值对映射(Maps)

下面的例子就是 Map:

$hello: (key1: value1, key2: value2, key3: value3);

与 list 不同的是,map 外面总是有小括号,并且其中的键值对总是用逗号隔开。其中的键和值都可以是任意 sass 对象。

与 list 相同的是,map 大部分时候也是用 sass 的map相关的函数来操作。

任何使用 list 的地方也可以使用 map。比如(key1: value1, key2: value2)可以被当作是2层列表 key1 value1, key2 value2

#运算

#数字运算

Sass 支持标准的算术运算,加+,减-,乘*,除/ 和 模%。 注意,Sass 在进行算术运算的时候会保留单位,所以你也不应该将不兼容的单位放在一起运算(比如把使用px为单位的数字和使用em为单位的数字作加法)。相同单位的两个数相乘也会出现平方单位(10px * 10px = 100px * px),而px * px并不是一个合法的 CSS 单位。

比较运算符<, >, <=, >=也可以用于 Sass 中的数字。 等于和不等于运算符 ==, !=则适用于 Sass 所有数据类型。

#除法和 /

注意,因为在有些 CSS 属性中也会有符号/,所以在 Sass 中除法运算符/会有两种不同的作用。默认情况下,/符号会当作字面字符串,而不是除法运算符。然而,有以下3种特殊情况,/会被当做除法运算符。

  1. value或其中的一部分 是一个变量,或者是一个函数的返回值
  2. value被包含在小括号中,除非value是一个Sass list
  3. value中存在另一个算术运算
scss
p {
  font: 10px/8px;               // 不作除法
  $width: 1000px;
  width: $width/2;              // 1 使用了变量,作除法
  width: round(1.5)/2;          // 1 使用了函数,作除法
  height: (500px/2);            // 2 使用了小括号,作除法
  margin-left: 5px + 8px/2px;   // 2 使用了 + ,作除法
  font: (italic bold 10px/8px); // 2 在一个list中,不作除法
}
css
p {
  font: 10px/8px;
  width: 500px;
  width: 1;
  height: 250px;
  margin-left: 9px;
  font: italic bold 10px/8px;
}

#减法,负数和 -

符号 - 在 CSS 和 Sass 可能意味着减法符号(比如5px - 3px),一个负数(比如-3px),或者是一个属性名的一部分(比如font-weight)。大部分时候,应该很容易区分其作用,但有时却会比较麻烦。以下是一些比较保险的规则:

在解释 - 作何作用的时候,按以下顺序:

  1. - 作为识别符(identifier)的一部分的时候,比如 a-1 会当作不带引号的字符串。唯一例外的是单位后面的 -,比如 5px-3px 相当于 5px - 3px,也就是减法。
  2. - 在2个数字之间,中间没有空格。会被当做减法,所以 1-2 相当于 1 - 2
  3. - 在1个数字字面值前。会被当做负号。比如 1 -2 会被当做一个包含 1-2 的 list
  4. - 在2个数字(包括数字变量)之间,无论是否有空格。也会被当做减法。比如 1 -$var 相当于 1 - $var
  5. 一个前的 -,会被当做负号

#颜色值的运算

所有的算术运算也都可以用于颜色值,只是要注意运算时是rgb分开进行计算的。比如下面的例子中,计算会被分成01 + 04 = 05, 02 + 05 = 07 以及 03 + 06 = 09:

scss
p {
  color: #010203 + #040506;
}
css
p {
  color: #050709;
}

通常使用颜色函数(color functions)来进行颜色的操作。

颜色值 和 数字值 之间也是可以进行算术运算的,比如下面的例子中,计算会被分成01 * 2 = 02, 02 * 2 = 04 以及 03 * 2 = 06:

scss
p {
  color: #010203 * 2;
}
css
p {
  color: #020406;
}

要注意,对于有 alpha 通道的颜色值,在算术运算时,2个操作数都必须是含有相同 alpha 值的颜色值。 并且运算时,不影响 alpha 值,比如:

scss
p {
  color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
css
p {
  color: rgba(255, 255, 0, 0.75);
}

如果要调整 alpha 通道值,可以使用 opacifytransparentize 函数。

#字符串运算

加号 +,可以用来连接字符串:

scss
p {
  cursor: e + -resize;
}
css
p {
  cursor: e-resize;
}

对于 带引号字符串 和 不带引号字符串 之间的 + 运算的结果是否带引号,取决于 + 左边的值。

scss
p:before {
  content: "Foo " + Bar;
  font-family: sans- + "serif";
}
css
p:before {
  content: "Foo Bar";
  font-family: sans-serif;
}

在字符串文本中,可以待插入的表达式或变量放到TODO中来进行插入:

scss
p:before {
  content: "I ate #{5 + 10} pies!";
}
css
p:before {
  content: "I ate 15 pies!";
}

Null值在进行 字符串插入 时,会被当作 空字符串:

scss
$value: null;
p:before {
  content: "I ate #{$value} pies!";
}
css
p:before {
  content: "I ate  pies!";
}

#布尔值运算

对于布尔值,Sass中可以使用运算符 and, or 以及 not

#list 运算

通常适用 list 函数来进行 list 的操作。

#小括号

和其他语言一样,小括号可以用来预想运算的顺序:

scss
p {
  width: 1em + (2em * 3);
}
css
p {
  width: 7em;
}

#插入 #{xxx}

property 和 selector 都可以使用#{xxx}的方式来插入:

scss
$name: foo;
$attr: border;
p.#{$name} {
  #{$attr}-color: blue;
}
css
p.foo {
  border-color: blue;
}

value 中也可以使用#{xxx}插入。当然大部分时候我们都会直接使用变量,但使用#{xxx}式插入,它旁边的运算符会被当做字面字符串,比如下面例子/不会被当做除法符号:

scss
p {
  $font-size: 12px;
  $line-height: 30px;
  font: #{$font-size}/#{$line-height};
}
css
p {
  font: 12px/30px;
}

#变量默认值

在进行变量赋值时,在后加上 !default 表示如果这个变量已经被赋值了,则不进行重复赋值;如果该变量还没有值,则进行赋值。

scss
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;

#main {
  content: $content;
  new-content: $new_content;
}
css
#main {
  content: "First content";
  new-content: "First time reference";
}

使用!default时,值为null的变量会被当做没有值。

scss
$content: null;
$content: "Non-null content" !default;

#main {
  content: $content;
}
css
#main {
  content: "Non-null content";
}

#@ 规则 和 指令

#@import

Sass 扩展了 CSS 的 @import 功能,在 Sass 文件中可以 import 其他 SCSS 和 Sass 文件。被 import 的文件中的 变量 和 mixin 都可以在主文件中直接使用。

import Sass 文件时,@import 后面接文件名。但是如果是以下情况时,则当做 CSS 的@import

如果上面的条件不满足,文件扩展名是 .scss.sass 时,该文件会被 import, 如果没有包含扩展名,则 Sass 会尝试查找使用该文件名,扩展名为 .scss.sass的文件,并 import 它。

例如,有文件 foo.scss, 其中内容为:

a {
  color: red;
}

则:

scss
/* import 之前 */
@import "foo";
/* import 之后 */
css
/* import 之前 */
a {
  color: red;
}

/* import 之后 */

@import "foo", "bar"; 可以同时 import 文件 foobar

#部分(Partials)

当一个目录中又多个 Sass 文件时,很多时候我们并不希望把所有这些文件都编译成一个单独的 CSS 文件,这时可以给不用编译成单独 CSS 文件的 Sass 文件的文件名前面加上下划线_。在 import 这样的文件的时候,我们并需要加上下划线。

比如你有个文件 _bar.scss,因为有文件名以下划线开头,所以不会生成_bar.css文件。但你可以在你的主 sass 文件中,import 该文件。

scss
@import "bar";
css
/* in _bar.scss */
a {
  color: green;
}

#嵌套(Nested) @import

我们可以在 CSS rule 或 @media rule 中进行@import。 要注意的是,CSS selector 也会嵌套。

比如文件 _baz.scss 中包含如下内容:

.example {
  color: red;
}

则:

scss
#main {
  @import "baz";
}
css
#main .example {
  color: red;
}

#@media

Sass 中的 @media 的功能和 CSS 中的类似,但在 Sass 中 @media 可以被嵌套在 CSS rule中。如果 @media 嵌套在 CSS rule 中,则作用时它会自动冒泡到顶层。比如:

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

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

@media queries 之间也可以进行相互嵌套。这时 queries 之间使用 and 进行合并。如:

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

@midia queries 中也可以在 feature namesfeature values 的地方使用 sass 表达式,包括变量,函数,运算操作符。比如:

scss
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;

@media #{$media} and ($feature: $value) {
  .sidebar {
    width: 500px;
  }
}
css
@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
  .sidebar {
    width: 500px;
  }
}

#@extend

@extend 指令可以用来继承另一个 selector 的样式。比如:

scss
.a {
  border: 1px #f00;
}
.b {
  @extend .a;
  border-width: 3px;
}
css
.a, .b {
  border: 1px #f00;
}

.b {
  border-width: 3px;
}

从上面的例子中可以看出来,实际上 Sass 就是在 .a 处插入 .b

实际上,其他包含了 .a 的 rule,也会被 .b 所使用。比如:

scss
.error {
  border: 1px #f00;
}
.error.minor {
  background-color: #eee;
}
.critial {
  @extend .error;
  color: tomato;
}
css
.error, .critial {
  border: 1px #f00;
}

.error.minor, .minor.critial {
  background-color: #eee;
}

.critial {
  color: tomato;
}

@extend 不仅适用于 class selector,对于其他 selector 也适用,比如 .special.coola:hover, a.user[href^="http://"]等。比如

scss
.hoverlink {
  @extend a:hover;
}
a:hover {
  text-decoration: underline;
}
css
a:hover, .hoverlink {
  text-decoration: underline;
}

和前面error.minor的例子一样, 其他任何包含 a:hover 的规则也会被用于 hoverlink, 及时其中包含其他 selector。 比如:

scss
.hoverlink {
  @extend a:hover;
}
.comment a.user:hover {
  font-weight: bold;
}
css
.comment a.user:hover, .comment .user.hoverlink {
  font-weight: bold;
}

#只用于 @extend 的 selector

使用 % 可以定义一个只用于 extened 的 selector,它相当于占位(placeholder) selector。这样的 selector 及其 rule 不会直接生成到 CSS 中。在定义时,相当于把符号 % 用到可以用在符号 # 和符号 . 的位置。比如:

scss
/* before */
#context a%extreme {
  color: blue;
}
/* after */
css
/* before */
/* after */

然后我们可以 @extend 这样一个占位 selector。比如:

scss
.outer %inner {
  color: red;
}

.content {
  @extend %inner;
}
css
.outer .content {
  color: red;
}

#@at-root

@at-root 可以让原本嵌套在其他 selector 中的 selector 置于顶层。比如:

scss
.parent {
  color: red;

  @at-root {
    .child1 { font-size: 16px; }
    .child2 { border-width: 2px; }
  }

  .step-child { background-color: #ccc; }
}
css
.parent {
  color: red;
}

.child1 {
  font-size: 16px;
}

.child2 {
  border-width: 2px;
}

.parent .step-child {
  background-color: #ccc;
}

#@debug

@debug 可以将 Sass 表达式的值打印到标准错误。可以方便的进行 debug。比如:

@debug 10em + 12em;

会在终端输出:

Line 1 DEBUG: 22em

#@warn

@warn 也可以将 Sass表达式的值打印到标准错误。@warn@debug 的区别在于,@warn在 CLI 选项 --quiet 或 Sass 选项 :quiet进行关闭,另外 @warn 中打印的消息也会包含 warning 的地方。

例子:

scss
@mixin adjust-location($x, $y) {
  @if unitless($x) {
    @warn "Assuming #{$x} to be in pixels";
    $x: 1px * $x;
  }
  @if unitless($y) {
    @warn "Assuming #{$y} to be in pixels";
    $y: 1px * $y;
  }
  position: relative; left: $x; top: $y;
}
css

#@error

@error 用来抛出一个错误,其中也会伴随相应的 stack trace。很适合用来对 mixins函数 中的参数进行合法性验证。比如:

scss
@mixin adjust-location($x, $y) {
  @if unitless($x) {
    @error "$x may not be unitless, was #{$x}.";
  }
  @if unitless($y) {
    @error "$y may not be unitless, was #{$y}.";
  }
  position: relative; left: $x; top: $y;
}
css

#控制指令(Directives)和表达式(Expressions)

#if()

if() 是 Sass 中的内置函数

下面的例子中,第一表达式回返回1px, 而第二个会返回 2px

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

#@if

@if 指令使用一个 sass 表达式作为参数。如果该表达式的返回 falsenull 以外的值,则该指令中嵌套的 style 会被使用。比如:

scss
p.with-border {
  @if 1 + 1 == 2 { border: 1px solid;  }
  @if 5 < 3      { border: 2px dotted; }
  @if null       { border: 3px double; }
}
css
p.with-border {
  border: 1px solid;
}

@if 指令后面可以再接多个 @else if 语句,或者一个 @else 语句。比如:

scss
$type: monster;
p.colorful {
  @if $type == ocean {
    color: blue;
  } @else if $type == matador {
    color: red;
  } @else if $type == monster {
    color: green;
  } @else {
    color: black;
  }
}
css
p.colorful {
  color: green;
}

#@for

@for 指令用于构建循环语句。

语法:

  1. @for $var from <start> through <end>
  2. @for $var from <start> to <end>

其中 $var 被称为 counter,当然你也可以写成 $i$j。 而 <start><end> 都必须是可以返回整数的 Sass 表达式。 如果 <start><end> 大,则 $var 会进行递减而不是递增。

使用第1种语法,使用 through,则循环的时候 $var 的值会从 <start> 每次加1一直到 <end>(包含<end>),。而使用第2种语法,使用 to,循环时 $var 也是从 <start> 逐次加1直到 <end>,但不会包含 <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;
}

#@each

@each 指令也用于构建循环语句。

语法:

@each $var in <list or map>

其中 <list or map> 必须是 list 或者 map 或者是可以返回 list 或 map 的 Sass 表达式。

在循环的过程中 $var 的值会被设为 list 或 map 中的各项。

例子:

scss
@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}
css
.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");
}

@each 也可以使用多个 counter。

语法:

@each $var1, $var2, ... in <list>

其中 <list> 是一个包含多个列表的列表

例如:

scss
@each $animal, $color, $cursor in (puma, black, default),
                                  (sea-slug, blue, pointer),
                                  (egret, white, move) {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
    border: 2px solid $color;
    cursor: $cursor;
  }
}
css
.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;
}

使用 map 的话是这样的。

scss
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
  #{$header} {
    font-size: $size;
  }
}
css
h1 {
  font-size: 2em;
}

h2 {
  font-size: 1.5em;
}

h3 {
  font-size: 1.2em;
}

#@while循环

用法:

@while <expression> {
  ...
}

@while 循环会一直到表达式 <expression> 的值为 false 时才停止。

scss
$i: 6;
@while $i > 0 {
  .item-#{$i} { width: 2em * $i; }
  $i: $i - 2;
}
css
.item-6 {
  width: 12em;
}

.item-4 {
  width: 8em;
}

.item-2 {
  width: 4em;
}

#@mixin

mixin 可以用来定义可重用的 CSS style。 mixin 可以接收参数,这可以让我们获得更灵活的 style。

#定义和使用 mixin

指令 @mixin 可以定义一个 mixin,指令 @include 可以用来使用一个 mixin。

下面的例子定义并使用了一个叫 large-text 的 mixin:

scss
/* 定义 mixin */
@mixin large-text {
  font: {
    family: Arial;
    size: 20px;
    weight: bold;
  }
  color: #ff0000;
}

/* 使用 mixin */
.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}
css
/* 定义 mixin */
/* 使用 mixin */
.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px;
}

在 mixin 中,也可以包含 selector,也可以使用 & 符号来引用父级 selector。

比如:

scss
@mixin clearfix {
  display: inline-block;
  &:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
  }
  * html & { height: 1px }
}
css

mixin 也可以直接用在顶层(不在任何 selector rule 中)。比如:

scss
@mixin silly-links {
  a {
    color: blue;
    background-color: red;
  }
}

@include silly-links;
css
a {
  color: blue;
  background-color: red;
}

定义 mixin 的时候,也可以使用其他 mixin:

scss
@mixin compound {
  @include highlighted-background;
  @include header-text;
}

@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }

h2.highlight {
  @include compound;
}
css
h2.highlight {
  background-color: #fc0;
  font-size: 20px;
}

#带参数的 mixin

#定义和使用带参数的 mixin

例子:

scss
@mixin sexy-border($color, $width) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}

p { @include sexy-border(blue, 1in); }
css
p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed;
}

也可以使用默认变量,所谓默认变量就是在定义是给了默认值的变量。使用这个 mixin 的时候,如果没有给这个变量传参数,则会使用定义时的默认值。例如:

scss
@mixin sexy-border($color, $width: 1in) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue); }
h1 { @include sexy-border(blue, 2in); }
css
p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed;
}

h1 {
  border-color: blue;
  border-width: 2in;
  border-style: dashed;
}

#使用关键字参数

在使用 mixin 的时候,我们也可以把传入的参数写成 键值对 的形式。这样可以让代码明确已读,而且使用的时候也不用在意传参的顺序。

scss
p {
  @include sexy-border($color: blue);
}

h1 {
  @include sexy-border( $width: 2in, $color: blue);
}
css
p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed;
}

h1 {
  border-color: blue;
  border-width: 2in;
  border-style: dashed;
}

#不定参数

有时我们希望使用非固定数量的参数 mixin。 比如 box-shadow 可以接受多个 shadow 样式作为参数, 对于这种情况就要使用 不定参数 的 mixin。 在定义这种 mixin 的时候,可以在参数列表的最后一个参数后面加上...,这时这个参数就会变成不定参数。比如:

scss
@mixin box-shadow($shadows...) {
  -moz-box-shadow: $shadows;
  -webkit-box-shadow: $shadows;
  box-shadow: $shadows;
}

.shadows {
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}
css
.shadows {
  -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}

在调用 mixin 的时候,也可以使用不定参数。

其实就是对 list 和 map 进行展开。下面例子分别展示了使用 list 和 map :

scss
@mixin colors($text, $background, $border) {
  color: $text;
  background-color: $background;
  border-color: $border;
}

$values: #ff0000, #00ff00, #0000ff;
.primary {
  @include colors($values...);
}

$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
  @include colors($value-map...);
}
css
.primary {
  color: #ff0000;
  background-color: #00ff00;
  border-color: #0000ff;
}

.secondary {
  color: #00ff00;
  background-color: #0000ff;
  border-color: #ff0000;
}

你也可以同时 list 和 map 展开,只要你在调用的时候,把 list 放在 map 前面。

你可以使用 不定参数 重新封装一个 mixin,这样你可以在不改变这个原 mixin 的情况下,添加额外的 style。 比如:

scss
@mixin stylish-mixin($color, $width) {
  color: $color;
  width: $width;
}

@mixin wrapped-stylish-mixin($args...) {
  font-weight: bold;
  @include stylish-mixin($args...);
}

.stylish {
  // 参数 $witdh 会被作为关键字参数传给 "stylish-mixin"
  @include wrapped-stylish-mixin(#00ff00, $width: 100px);
}
css
.stylish {
  font-weight: bold;
  color: #00ff00;
  width: 100px;
}

#整个 block 内容作为 mixin 参数

在 mixin 定义中,可以使用指令 @content 来获取这个 block 的内容。在一个 mixin 中 @content 也可以多次使用。

比如:

scss
@mixin apply-to-ie6-only {
  * html {
    @content;
  }
}
@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}
css
* html #logo {
  background-image: url(/logo.gif);
}

要注意,传给 mixin 的 block 会使用它定义时的作用域,而不是 mixin 的内部作用域。下面的例子中,@content 在转换的时候,变量 $colorsize 并不会使用 mixin 自己 local 的 $colorsize 变量,而是原 block 定义时所在作用域的相应变量。

scss
$color: white;
@mixin colors($color: blue, $size: 200px) {
  background-color: $color;
  @content;
  border-color: $color;
  width: $size;
}
.colors {
  $size: 1em;
  @include colors {
    color: $color;
    font-size: $size;
  }
}
css
.colors {
  background-color: blue;
  color: white;
  font-size: 1em;
  border-color: blue;
  width: 200px;
}

#函数(Functions)

@function 指令用来定义个 function,在 function 定义中使用 @return 指令来返回一个值。

在调用 function 时,并不需要 @include 指令。而且也可以使用关键字参数。

scss
$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

#sidebar { width: grid-width(5); }

#sidebar_2 { width: grid-width($n: 10); }
css
#sidebar {
  width: 240px;
}

#sidebar_2 {
  width: 490px;
}

#Sass 内置函数

Sass 中定义了一些有用的函数,完整的函数列表在这

比如这里调用操作颜色的函数 hsl()

scss
p {
  color: hsl(0, 100%, 50%);
}
css
p {
  color: red;
}

#关键字参数

Sass 在调用时可以使用关键词参数,使用关键词参数可以提高易读性。同时也不用在意参数顺序。比如上面的例子可以写成:

scss
p {
  color: hsl($hue: 0, $lightness: 50%, $saturation: 100%);
}
css
p {
  color: red;
}