本文发表于 641 天前,其中的信息可能已经事过境迁
文章摘要
加载中...|
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结 投诉

一、Sass是什么?

Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。使用 Sass 以及 Sass 的样式库(如 Compass)有助于更好地组织管理样式文件,以及更高效地开发项目。

1.特色功能

  • 完全兼容 CSS3
  • 在 CSS 基础上增加变量、嵌套 (nesting)、混合 (mixins) 等功能
  • 通过函数进行颜色值与属性值的运算
  • 提供控制指令 (control directives)等高级功能
  • 自定义输出格式

2.语法格式

Sass 有两种语法格式。首先是 SCSS (Sassy CSS) —— 也是本文示例所使用的格式 —— 这种格式仅在 CSS3 语法的基础上进行拓展,所有 CSS3 语法在 SCSS 中都是通用的,同时加入 Sass 的特色功能。此外,SCSS 也支持大多数 CSS hacks 写法以及浏览器前缀写法 (vendor-specific syntax),以及早期的 IE 滤镜写法。这种格式以 .scss 作为拓展名。

ps: 一般不会写下面这种语法格式,了解一下 -- liuwy

另一种也是最早的 Sass 语法格式,被称为缩进格式 (Indented Sass) 通常简称 "Sass",是一种简化格式。它使用 "缩进" 代替 "花括号" 表示属性属于某个选择器,用 "换行" 代替 "分号" 分隔属性,很多人认为这样做比 SCSS 更容易阅读,书写也更快速。缩进格式也可以使用 Sass 的全部功能,只是与 SCSS 相比个别地方采取了不同的表达方式,具体请查看 the indented syntax reference。这种格式以 .sass 作为拓展名。

二、Sass 的使用

1.安装 sass

bash
npm i sass -D

2.编写 npm script

在 package.json 中加入此命令

json
"compile:sass": "sass sass/main.scss css/style.css -w"

使用命令

bash
npm run compile:sass

命令描述

  • sass : 执行 sass
  • sass/main.scss : 待编译的 sass 文件相对路径
  • css/style.css : 编译后的 css 目标文件相对路径
  • -w : --watch 监听文件变化,执行命令

三、Sass 对 CSS 的功能扩展

1.嵌套规则

scss
#main p {
  color: #00ff00;
  width: 97%;

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

2.父选择器&

使用方式可以尽情想象

scss
a {
  font-weight: bold;
  text-decoration: none;
  &:hover {
    text-decoration: underline;
  }
  body.firefox & {
    font-weight: normal;
  }
}
#main {
  color: black;
  &-sidebar {
    border: 1px solid;
  }
}

3.属性嵌套

scss
.funky {
  font: {
    family: fantasy;
    size: 30em;
    weight: bold;
  }
}

4.占位符选择器 %foo

Sass 额外提供了一种特殊类型的选择器:占位符选择器 (placeholder selector)。与常用的 id 与 class 选择器写法相似,只是 #. 替换成了 %。必须通过 @extend 指令调用, 当占位符选择器单独使用时(未通过 @extend 调用),不会编译到 CSS 文件中。

5.注释

scss
/* This comment is
 * several lines long.
 * since it uses the CSS comment syntax,
 * it will appear in the CSS output. */
body {
  color: black;
}

// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a {
  color: green;
}

6.SassScript

ps: 这部分用到的基本只有变量,了解一下

6.1 变量 $

SassScript 最普遍的用法就是变量,变量以美元符号开头,赋值方法与 CSS 属性的写法一样:

scss
$width: 5em;

直接使用即调用变量:

css
#main {
  width: $width;
}

变量支持块级作用域,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不在嵌套规则内定义的变量则可在任何地方使用(全局变量)。将局部变量转换为全局变量可以添加 !global 声明:

scss
#main {
  $width: 5em !global;
  width: $width;
}

#sidebar {
  width: $width;
}

6.2 数据类型

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

  • 数字,1, 2, 13, 10px
  • 字符串,有引号字符串与无引号字符串,"foo", 'bar', baz
  • 颜色,blue, #04a3f9, rgba(255,0,0,0.5)
  • 布尔型,true, false
  • 空值,null
  • 数组 (list),用空格或逗号作分隔符,1.5em 1em 0 2em, Helvetica, Arial, sans-serif
  • maps, 相当于 JavaScript 的 object,(key1: value1, key2: value2)

SassScript 也支持其他 CSS 属性值,比如 Unicode 字符集,或 !important 声明。然而Sass 不会特殊对待这些属性值,一律视为无引号字符串。

6.2.1 字符串

SassScript 支持 CSS 的两种字符串类型:有引号字符串 (quoted strings),如 "Lucida Grande" 'http://sass-lang.com';与无引号字符串 (unquoted strings),如 sans-serif bold,在编译 CSS 文件时不会改变其类型。只有一种情况例外,使用 #{} (interpolation) 时,有引号字符串将被编译为无引号字符串,这样便于在 mixin 中引用选择器名:

scss
@mixin firefox-message($selector) {
  body.firefox #{$selector}:before {
    content: "Hi, Firefox users!";
  }
}
@include firefox-message(".header");

编译为

css
body.firefox .header:before {
  content: "Hi, Firefox users!";
}
6.2.2 数组

数组 (lists) 指 Sass 如何处理 CSS 中 margin: 10px 15px 0 0 或者 font-face: Helvetica, Arial, sans-serif 这样通过空格或者逗号分隔的一系列的值。事实上,独立的值也被视为数组 —— 只包含一个值的数组。

数组本身没有太多功能,但 Sass list functions 赋予了数组更多新功能:nth 函数可以直接访问数组中的某一项;join 函数可以将多个数组连接在一起;append 函数可以在数组中添加新值;而 @each 指令能够遍历数组中的每一项。

数组中可以包含子数组,比如 1px 2px, 5px 6px 是包含 1px 2px5px 6px 两个数组的数组。如果内外两层数组使用相同的分隔方式,需要用圆括号包裹内层,所以也可以写成 (1px 2px) (5px 6px)。变化是,之前的 1px 2px, 5px 6px 使用逗号分割了两个子数组 (comma-separated),而 (1px 2px) (5px 6px) 则使用空格分割(space-separated)。

当数组被编译为 CSS 时,Sass 不会添加任何圆括号(CSS 中没有这种写法),所以 (1px 2px) (5px 6px)1px 2px, 5px 6px 在编译后的 CSS 文件中是完全一样的,但是它们在 Sass 文件中却有不同的意义,前者是包含两个数组的数组,而后者是包含四个值的数组。

() 表示不包含任何值的空数组(在 Sass 3.3 版之后也视为空的 map)。空数组不可以直接编译成 CSS,比如编译 font-family: () Sass 将会报错。如果数组中包含空数组或空值,编译时将被清除,比如 1px 2px () 3px1px 2px null 3px

基于逗号分隔的数组允许保留结尾的逗号,这样做的意义是强调数组的结构关系,尤其是需要声明只包含单个值的数组时。例如 (1,) 表示只包含 1 的数组,而 (1 2 3,) 表示包含 1 2 3 这个以空格分隔的数组的数组。

6.3 运算

数字运算

scss
p {
  width: 1in + 8pt;
}

6.4 函数

SassScript 定义了多种函数,有些甚至可以通过普通的 CSS 语句调用:

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

编译为

css
p {
  color: #ff0000;
}

Sass 函数允许使用关键词参数 (keyword arguments),上面的例子也可以写成:

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

虽然不够简明,但是阅读起来会更方便。关键词参数给函数提供了更灵活的接口,以及容易调用的参数。关键词参数可以打乱顺序使用,如果使用默认值也可以省缺,另外,参数名被视为变量名,下划线、短横线可以互换使用。

通过 Sass::Script::Functions 查看完整的 Sass 函数列表,参数名,以及如何自定义函数。

6.5 插值语句

通过 #{} 插值语句可以在选择器或属性名中使用变量:

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

编译为

css
p.foo {
  border-color: blue;
}

#{} 插值语句也可以在属性值中插入 SassScript,大多数情况下,这样可能还不如使用变量方便,但是使用 #{} 可以避免 Sass 运行运算表达式,直接编译 CSS。

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

编译为

css
p {
  font: 12px/30px;
}

四、指令系统

1.@-Rules 与 延伸指令

ps: 注意力集中于@extend@mixin -- liuwy

Sass 支持所有的 CSS3 @-Rules,以及 Sass 特有的 "指令"(directives)

1.1 导入指令 @import

Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。被导入的文件将合并编译到同一个 CSS 文件中,另外,被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。

通常,@import 寻找 Sass 文件并将其导入,但在以下情况下,@import 仅作为普通的 CSS 语句,不会导入任何 Sass 文件。

  • 文件拓展名是 .css
  • 文件名以 http:// 开头;
  • 文件名是 url()
  • @import 包含 media queries。

如果不在上述情况内,文件的拓展名是 .scss.sass,则导入成功。没有指定拓展名,Sass 将会试着寻找文件名相同,拓展名为 .scss.sass 的文件并将其导入。

scss
@import "foo.scss";

scss
@import "foo";

都会导入文件 foo.scss,但是

scss
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);

编译为

css
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);

Sass 允许同时导入多个文件,例如同时导入 rounded-corners 与 text-shadow 两个文件:

scss
@import "rounded-corners", "text-shadow";

导入文件也可以使用 #{ } 插值语句,但不是通过变量动态导入 Sass 文件,只能作用于 CSS 的 url() 导入方式:

scss
$family: unquote("Droid+Sans");
@import url("http://fonts.googleapis.com/css?family=\#{$family}");

编译为

css
@import url("http://fonts.googleapis.com/css?family=Droid+Sans");

大多数情况下,一般在文件的最外层(不在嵌套规则内)使用 @import,其实,也可以将 @import 嵌套进 CSS 样式或者 @media 中,与平时的用法效果相同,只是这样导入的样式只能出现在嵌套的层中。

假设 example.scss 文件包含以下样式:

scss
.example {
  color: red;
}

然后导入到 #main 样式内

scss
#main {
  @import "example";
}

将会被编译为

css
#main .example {
  color: red;
}

1.2 媒体查询指令 @media

Sass 中 @media 指令与 CSS 中用法一样,只是增加了一点额外的功能:允许其在 CSS 规则中嵌套。如果 @media 嵌套在 CSS 规则内,编译时,@media 将被编译到文件的最外层,包含嵌套的父选择器。这个功能让 @media 用起来更方便,不需要重复使用选择器,也不会打乱 CSS 的书写流程。

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 允许互相嵌套使用,编译时,Sass 自动添加 and

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

编译为

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

@media 甚至可以使用 SassScript(比如变量,函数,以及运算符)代替条件的名称或者值:

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;
  }
}

1.3 延伸指令 @extend

在设计网页的时候常常遇到这种情况:一个元素使用的样式与另一个元素完全相同,但又添加了额外的样式。通常会在 HTML 中给元素定义两个 class,一个通用样式,一个特殊样式。假设现在要设计一个普通错误样式与一个严重错误样式,一般会这样写:

html
<div class="error seriousError">Oh no! You've been hacked!</div>

样式如下

css
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  border-width: 3px;
}

麻烦的是,这样做必须时刻记住使用 .seriousError 时需要参考 .error 的样式,带来了很多不便:比如加重维护负担,导致 bug,或者给 HTML 添加无语意的样式。

使用 @extend 可以避免上述情况,告诉 Sass 将一个选择器下的所有样式继承给另一个选择器。

scss
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

上面代码的意思是将 .error 下的所有样式继承给 .seriousErrorborder-width: 3px; 是单独给 .seriousError 设定特殊样式,这样,使用 .seriousError 的地方可以不再使用 .error

其他使用到 .error 的样式也会同样继承给 .seriousError,例如,另一个样式 .error.intrusion 使用了 hacked.png 做背景,<div class="seriousError intrusion"> 也同样会使用 hacked.png 背景。

css
.error.intrusion {
  background-image: url("/image/hacked.png");
}
1.3.1 @extend原理

@extend 的作用是将重复使用的样式 (.error) 延伸 (extend) 给需要包含这个样式的特殊样式(.seriousError),刚刚的例子:

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;
}

当合并选择器时,@extend 会很聪明地避免无谓的重复,.seriousError.seriousError 将编译为 .seriousError,不能匹配任何元素的选择器(比如 #main#footer )也会删除。

1.3.2 延伸复杂的选择器

Class 选择器并不是唯一可以被延伸 (extend) 的,Sass 允许延伸任何定义给单个元素的选择器,比如 .special.coola:hover 或者 a.user[href^="http://"] 等,例如:

scss
.hoverlink {
  @extend a:hover;
}

同 class 元素一样,a:hover 的样式将继承给 .hoverlink

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

编译为

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

与上面 .error.intrusion 的例子一样,所有 a:hover 的样式将继承给 .hoverlink,包括其他使用到 a:hover 的样式,例如:

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

编译为

css
.comment a.user:hover,
.comment .user.hoverlink {
  font-weight: bold;
}
1.3.3 多重延伸

同一个选择器可以延伸给多个选择器,它所包含的属性将继承给所有被延伸的选择器:

scss
.error {
  border: 1px #f00;
  background-color: #fdd;
}
.attention {
  font-size: 3em;
  background-color: #ff0;
}
.seriousError {
  @extend .error;
  @extend .attention;
  border-width: 3px;
}

编译为

css
.error,
.seriousError {
  border: 1px #f00;
  background-color: #fdd;
}

.attention,
.seriousError {
  font-size: 3em;
  background-color: #ff0;
}

.seriousError {
  border-width: 3px;
}

每个 .seriousError 将包含 .error.attention 下的所有样式,这时,后定义的样式享有优先权:.seriousError 的背景颜色是 #ff0 而不是 #fdd,因为 .attention.error 之后定义。

多重延伸可以使用逗号分隔选择器名,比如 @extend .error, .attention;@extend .error; @extend.attention 有相同的效果。

1.3.4 继续延伸

当一个选择器延伸给第二个后,可以继续将第二个选择器延伸给第三个,例如:

scss
.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%;
}

现在,每个 .seriousError 选择器将包含 .error 的样式,而 .criticalError 不仅包含 .seriousError 的样式也会同时包含 .error 的所有样式,上面的代码编译为:

css
.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%;
}
1.3.5 @extend-Only 选择器

有时,需要定义一套样式并不是给某个元素用,而是只通过 @extend 指令使用,尤其是在制作 Sass 样式库的时候,希望 Sass 能够忽略用不到的样式。

如果使用普通的 CSS 规则,最后会编译出很多用不到的样式,也容易与其他样式名冲突,所以,Sass 引入了"占位符选择器" (placeholder selectors),看起来很像普通的 idclass 选择器,只是 #. 被替换成了 %。可以像 class 或者 id 选择器那样使用,当它们单独使用时,不会被编译到 CSS 文件中。

scss
// This ruleset won't be rendered on its own.
#context a%extreme {
  color: blue;
  font-weight: bold;
  font-size: 2em;
}

占位符选择器需要通过延伸指令使用,用法与 class 或者 id 选择器一样,被延伸后,占位符选择器本身不会被编译。

scss
.notice {
  @extend %extreme;
}

编译为

css
#context a.notice {
  color: blue;
  font-weight: bold;
  font-size: 2em;
}

2.混合指令

2.1 定义混合指令 @mixin

混合指令的用法是在 @mixin 后添加名称与样式,比如名为 large-text 的混合通过下面的代码定义:

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

混合也需要包含选择器和属性,甚至可以用 & 引用父选择器:

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

2.2 引用混合样式 @include

使用 @include 指令引用混合样式,格式是在其后添加混合名称,以及需要的参数(可选):

scss
.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}

编译为

css
.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px;
}

也可以在最外层引用混合样式,不会直接定义属性,也不可以使用父选择器。

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

编译为

css
a {
  color: blue;
  background-color: red;
}

混合样式中也可以包含其他混合样式,比如

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

混合样式中应该只定义后代选择器,这样可以安全的导入到文件的任何位置。

2.3 参数

参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号:

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;
}

混合指令也可以使用给变量赋值的方法给参数设定默认值,然后,当这个指令被引用的时候,如果没有给参数赋值,则自动使用默认值:

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;
}
2.3.1 关键词参数

混合指令也可以使用关键词参数,上面的例子也可以写成:

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

虽然不够简明,但是阅读起来会更方便。关键词参数给函数提供了更灵活的接口,以及容易调用的参数。关键词参数可以打乱顺序使用,如果使用默认值也可以省缺,另外,参数名被视为变量名,下划线、短横线可以互换使用。

2.3.2 参数变量

有时,不能确定混合指令需要使用多少个参数,比如一个关于 box-shadow 的混合指令不能确定有多少个 'shadow' 会被用到。这时,可以使用参数变量

赞赏博主
评论 隐私政策