# SCSS 简明上手

# 1. 关于 SCSS

众所周知,CSS 并不是编程语言,用它开发网页的样式是比较麻烦的,因为它没有变量,也没有语句,只有一条条单纯的描述。为了方便开发,『CSS 预处理器』被设计出来,它的思想是使用一种编程语言进行样式的开发,之后再转换成 CSS,以供使用。

Sass 就是一种 CSS 预处理器,而 Scss 则是它的进阶版。

使用 Sass/Scss 可以轻松地编写出清晰、无冗余、语义化的 CSS ,这是因为:

  1. Sass/Scss 提供了变量。通过变量可以让 CSS 的值变得可复用;

  2. Sass/Scss 支持嵌套。嵌套规则让 CSS 内可以继续嵌套 CSS,减少 CSS 重复的选择器,同样使得样式表的结构更加清晰;

  3. Sass/Scss 还提供了样式导入。可以将分散在多个 Sass 文件中的内容合并到一个 CSS 文件中,避免了大量使用原生 CSS 中 @import 性能问题,保持了 CSS 的整洁和可维护性。

在 Sass 之后,出了名为 Less 的预处理器,它更加简单且兼容 CSS,在 Ruby 社区之外的支持者远超过 Sass,不过,它的编程功能要弱于 Sass 。就是受 Less 的影响和挑战,Sass 才推出了 Scss,也全面兼容 CSS 。

无论是 Sass 还是 Scss ,在 vue-cli 中都是 node-sass 和 sass-loader 在进行编译处理。

# 2. 变量

变量用来存储需要在 CSS 中复用的信息,例如颜色和字体。Sass/Scss 通过 $ 符号去声明一个变量。

$active-color: #F90;                      // 定义 $active-color 变量
$active-border: 1px solid $active-color;  // 定义 $active-border 变量
.active {
  color: $active-color;                   // 使用 $active-color 变量
  border: $active-border;                 // 使用 $active-border 变量
};

编译后,上述例子中变量的变量将会被它们的值替换:

.active {
  color: #F90;
  border: 1px solid #F90;
}

在上述代码中,Scss 使用 $ 来定义变量,使用 : 连接变量的值,变量的值也可以是一连串的属性,像上面的 $active-border 变量一样,使用时直接在属性后接上变量名即可,经过转译就会变成标准的 CSS 样式。

注意,变量名使用『串型命名法』和『下划线命名法』都可以,而且两者通用,即,可以使用 $active_color$active_border 来调用变量。不过,根据 CSS 默认规则,推荐使用串型命名法。

# 3. @mixin

变量还有一个进阶版规则:混合器(mixin)。简单来说,就是一个包含着很多属性的变量。

@mixin rounded-corners {      // 构建 rounded-corners 圆角混合器
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

.notice {
  background-color: pink;
  border: 4px solid #00aa00;
  @include rounded-corners; // 调用 rounded-corners 圆角混合器
}

编译后,上述 scss 代码将会变为:

.notice {
  background-color: pink;
  border: 4px solid #00aa00;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

使用 @mixin 来给混合器命名,使用 @include 加混合器名来调用混合器。

# 4. 嵌套

Sass/Scss 允许开发人员以嵌套的方式使用 CSS,这样可以减少重复的 CSS 选择器的书写。

下面的例子表达了一个典型的网站导航样式:

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { 
    display: inline-block; 
  }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

大家注意上面代码中的 ullia 选择器都被嵌套在 nav 选择器当中使用,这是一种书写更高可读性 CSS 的良好方式,编译后产生的 CSS 代码如下:

nav ul {
  margin: 0;
  padding: 0;
  list-style: none; 
}

nav li {
  display: inline-block; 
}

nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none; 
}

Scss 允许 CSS 规则嵌套使用,父子规则将会呈现包含选择器的关系,例如:

/*===== SCSS =====*/
#main p {
  color: #00ff00;
  width: 97%;

  .redbox {
    background-color: #ff0000;
    color: #000000;
  }
}

上述代码会被编译成如下形式:

/*===== CSS =====*/
#main p {
  color: #00ff00;
  width: 97%; 
}
#main p .redbox {
  background-color: #ff0000;
  color: #000000; 
}

这样可以避免重复的使用父级选择器,从而达到简化 CSS 代码结构的目的,例如:

/*===== 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; 
}

# 5. 引用父级选择器 &

Scss 使用 & 关键字在 CSS 规则中引用父级选择器,例如在嵌套使用伪类选择器的场景下:

/*===== SCSS =====*/
a {
  font-weight: bold;
  text-decoration: none;
  &:hover { text-decoration: underline; }
  body.firefox & { font-weight: normal; }
}

/*===== CSS =====*/
a {
  font-weight: bold;
  text-decoration: none; 
}
a:hover {
  text-decoration: underline; 
}
body.firefox a {
    font-weight: normal;
}

无论 CSS 规则嵌套的深度怎样,关键字 & 都会使用父级选择器级联替换全部其出现的位置:

#main {
  color: black;
  a {
    font-weight: bold;
    &:hover { color: red; }
  }
}

/*===== CSS =====*/
#main {
  color: black; 
}
#main a {
  font-weight: bold; 
}
#main a:hover {
  color: red; 
}

& 必须出现在复合选择器开头的位置,后面再连接自定义的后缀,例如:

/*===== SCSS =====*/
#main {
  color: black;
  &-sidebar { border: 1px solid; }
}

/*===== CSS =====*/
#main {
  color: black; 
}
#main-sidebar {
  border: 1px solid; 
}

如果在父级选择器不存在的场景使用 & ,Scss 预处理器会报出错误信息。

# 6. @import 文件导入

与 CSS 自带的 @import 不同,Sass/Scss 的 @import 会在生成 CSS 时将引入的文件直接打包成一个 CSS 文件,无须发起额外的请求。所以,一般可以将不同作用的 .sass/.scss 文件分开写,最后引入一个文件中,在项目中只需调用最后引入所组建的文件即可:

// main.scss 文件内容
@import "./others/xxx.scss";  // 引入不同功能的 .scss 文件
@import "./others/yyy.scss";
@import "./others/zzz.scss";

如果不同文件中有同名的变量,Sass/Scss 会取最后一个变量使用。