[关闭]
@Shel 2017-09-02T06:40:49.000000Z 字数 5336 阅读 191

Sass & Compass 教程

Sass CSS Compass


语法篇

本篇重点
- 变量需要先声明后使用,且不存在变量提升。
- 嵌套使得样式结构清晰。
- 利用导入来分离代码,优化文件组织。
- 使用混合器封装重用的样式。
- 使用选择器继承减少样式重复。


1. 变量

SASS使用 $ 符号来标志变量。变量遵循先声明后使用的原则。

  1. body {
  2. font-size: $normal-size;
  3. }
  4. $normal-size: 14px;
  5. // 编译代码将会得到错误输出
  6. // Undefined variable: "$normal-size".

变量的声明具有作用域,我们甚至可以多次定义同一个变量的值。看下面的例子:

  1. $normal-size: 14px;
  2. body {
  3. $normal-size: 12px;
  4. font-size: $normal-size;
  5. }
  6. p {
  7. font-size: $normal-size;
  8. }
  9. $normal-size: 12px;
  10. h6 {
  11. font-size: $normal-size;
  12. }

编译后:

  1. body {
  2. font-size: 12px;
  3. }
  4. p {
  5. font-size: 14px;
  6. }
  7. h6 {
  8. font-size: 12px;
  9. }

在上面例子中,body内部声明的变量仅仅在其内部产生作用,同样的变量在p使用时没有被影响,然而,在同一作用域内,再次定义变量的值,只会影响后面的规则,前面的规则却没有被影响,这就是为何h6p字号结果不一。可见 SASS 的编译过程是从上到下依次执行的,但与 js 不一样的是它不存在变量的提升。
它的基本原理是:变量被值替换。


2. 嵌套

嵌套的存在使得我们编写规则更加直观,层次结构十分清晰。就像是在 html 标签之间相互嵌套一般。嵌套是为解决重复书写的问题。先来个直观的感受:

  1. // 在 CSS 中我们使用下面的形式来描述层级结构的样式
  2. article h1 {
  3. color: #333;
  4. }
  5. article p {
  6. color: #eee;
  7. }
  8. // SASS 使用嵌套写法
  9. article {
  10. h1 { color: #333 }
  11. p { color: #eee }
  12. }

这样的写法让我们很容易联想到DOM。
它的原理十分简单:当父选择器内存在子选择器的时候,SASS会将子选择(包括其内的规则)抽出,然后将父选择器放在子选择器前,并用一个空格将二者连接起来。
但有的时候我们并不希望使用空格连接,比如:

  1. a {
  2. color: red;
  3. }
  4. a:hover {
  5. color: green;
  6. }
  7. // 想要编译出上面的CSS,如果使用普通的嵌套写法
  8. a {
  9. color: red;
  10. :hover { color: green }
  11. }
  12. // 编译后
  13. a {
  14. color: red;
  15. }
  16. a :hover {
  17. color: green;
  18. }

很显然,伪类是不能直接嵌套书写的。
默认的前后选择器之间的连接是存在一个空格的,如果想要消除它,可以使用 & 符号。官方将它叫做父选择器,笔者给它起了一个接地气的名字:粘贴符😛,顾名思义,它会将前后两者紧紧的粘在一起,因此上述 SASS 正确的写法是:

  1. a {
  2. color: red;
  3. &:hover { color: green }
  4. }

除了重复书写选择器,重复书写属性名也是十分繁琐的工作。例如

  1. nav {
  2. border-style: solid;
  3. border-width: 1px;
  4. border-color: #ccc;
  5. }
  6. nav {
  7. border: solid 1px #ccc;
  8. border-left: 0;
  9. }

SASS的嵌套语法同样可以作用于属性名,只不过这回使用的连接符号不是空格而是 - 符号。

  1. nav {
  2. border: {
  3. style: solid;
  4. width: 1px;
  5. color: #ccc;
  6. }
  7. }
  8. nav {
  9. border: solid 1px #ccc {
  10. left: 0;
  11. }
  12. }

上述一直在讲述如何使用嵌套语法来简化我们的工作,但别忘了它给我们带来的另一大益处是,直观的视觉缩进使得结构清晰,行文优雅,易于阅读。


3. 导入@import

SASS的导入命令是在预编译阶段完成的,这有利于我们更好的组织管理样式文件。我们约定,在文件的开头使用 @import 命令导入外部文件。
有些文件是专门为了整合 @import 命令而编写的,并不需要编译成CSS文件,这样的文件官方称之为局部文件
并且约定,这样的文件名以下划线开头,而在导入时,省略开头的下划线

“导入”的存在使得变量声明结果不可预料,一般来说,后者覆盖前者。当为变量声明添加额外的 !default 标签时,意味着该值是变量的默认值,默认值的优先级是最低的,无论它在何处声明。

另外,CSS中存在也存在 @import,为了将两者区分开来,SASS的导入命令只针对SASS文件有效,凡以.sass或者.scss结尾的文件都可以在预编译阶段完成导入操作,而已 .css 结尾的文件会被保留下来,作为原生的CSS导入。如果你希望在预编译阶段导入CSS文件,不妨将.css后缀改成.scss后缀。


4. 静默注释

SASS 支持两种注释方式,一种是 CSS 标准注释,即/*...*/
另外一种类似于 JS 中的单行注释,以 // 开头一直到行末,这种注释方式称为静默注释,是用这种方式书写的注释会在预编译阶段自动抹去。


5. 混合器@mixin

如果读者曾经接触过 Less,那么这个概念你一定不会陌生。就如同 JS 中的函数一样,在样式的世界里,我们将重复使用的属性、规则包装在一个混合器中,并用 @mixin 来声明,然后在需要的地方,使用 @include 调用。先让我们来一个例子,直观的感受一下。

  1. @mixin no-bullets {
  2. list-style: none;
  3. li {
  4. list-style: {
  5. image: none;
  6. type: none;
  7. }
  8. margin: 0;
  9. }
  10. }
  11. ul.plain {
  12. @include no-bullets;
  13. }
  14. // 编译成CSS
  15. ul.plain {
  16. list-style: none;
  17. }
  18. ul.plain li {
  19. list-style-image: none;
  20. list-style-type: none;
  21. margin: 0;
  22. }

使用混合器最终目的是让它返回一堆属性和规则。
同时,我们还可以给它传递参数,使它输出不同的结果。
就如同 js 中函数的参数一样,混合器的参数其实就是在混合器内部声明的局部变量,我们可以在声明时给参数附上默认值。
而在调用混合器时,采用模式匹配给参数赋值。

  1. @mixin link-colors($normal,$hover:$normal,$visited:$normal) {
  2. color: $normal;
  3. &:hover { color: $hover; }
  4. &:visited { color: $visited; }
  5. }
  6. a {
  7. @include link-colors($normal: red,$hover: blue);
  8. }
  9. // 编译后的CSS
  10. a {
  11. color: red;
  12. }
  13. a:hover {
  14. color: blue;
  15. }
  16. a:visited {
  17. color: red;
  18. }

混合器很强大,就如同函数在 js 中一样的地位一样。然而无休止的滥用混合器会导致项目难以维护。

When you have only one hammer in your hand, you tend to look at all the problems as nails.
—— Maslow

一条经验法则:你能否为这个混合器找到一个短名字来描述这些属性修饰的样式。

对于混合器的命名,应该带有展示性的描述,侧重于表达当应用了这个样式后所带来的视觉效果。比如:"fancy-font"。这与CSS类名有所不同,两者容易混淆。

一种主流的命名方法:CSS类名使用语义化的描述,混合器的名字则采用展示性的描述。

鉴于上面的命名方法,我们得出,混合器的最佳使用点是封装重用的展示性样式。


6. 选择器继承 @extend

先看下面例子:

  1. // SASS
  2. .error {
  3. border: 1px red solid;
  4. color: red;
  5. background: #fff;
  6. }
  7. .danger-error {
  8. @extend .error;
  9. color: #fff;
  10. background: red;
  11. font-size: 1.8em;
  12. }
  13. // CSS
  14. .error, .danger-error {
  15. border: 1px red solid;
  16. color: red;
  17. background: #fff;
  18. }
  19. .danger-error {
  20. color: #fff;
  21. background: red;
  22. font-size: 1.8em;
  23. }

SASS 使用 @extend 来实现选择器继承。
它背后的基本原理是,如果 A 继承于 B ,那么在样式表的任何一处 B 都将会被 A,B 这一选择器组替换

继承是基于选择器的,常常是基于类选择器,上面说到类的命名应当是语义化的,因此,继承也是建立在语义化的关系上。就好比当你在编写样式时发现一个类是另一个类的细化的时候,比如上面.danger-error.error的细化。

同样的目的我们可以使用混合器来解决,然而混合器的使用会复制大段的代码,并且混合器的命名也会违背上面的原则,对此更好的解决方案是使用继承,上面的例子可以看出,继承只会增加选择器的数量,不会复制大量属性代码。

想要熟练的使用混合器与继承,需要日常反复练习,在实践中体会二者的侧重,这里笔者给出一条经验法则:为效果而混合,为逻辑而继承


7. 高级语法

本篇第一节到第六节主要是讲述SASS对于编写样式的拓展,从本节开始我们将从编程语言的角度来认识SASS。就如同其他编程语言一样,

与其他编程语言不一样的是,SASS有处理上的侧重点。我们知道SASS作为一种预编译语言,其最终产物是CSS文件,运行时处理的数据与传统意义上的数据类型有很大的差异。正确认识以及区分不同的数据类型是进行有效编程的基础。
笔者列出几条学习思路供读者参考:

7.1. 字符串 && 名字

举例:bold、auto、center、“Helvetica Neue”

字符串可以分为有引号无引号
无引号的字符串不能以数字和特殊字符开头,不能包括空格和一些特殊字符。
有引号的字符串可以包含除了双引号外的其他字符,一般又将有引号的字符串称为名字,例如举例中的第四项。

字符串最常用的操作符是+,得出的结果是否包含引号由左边决定。
举例:“foo" + 1 结果为 "foo1"

7.2. 数字

举例:5px、100%

一个数值包含两个部分:实际数值单位
数值可以做四则运算,因此+、-、*、/是其常用操作符,并且在做四则运算时,单位也会进行运算。
由于在CSS中存在特定值被正斜杠/分开的情况。为了兼容这种方式,SASS对以下情况进行除法运算。

SASS在做除法运算时结果通常是一个小数而不是整数(这通常也是我们想要的结果)。
SASS提供了常用的数学操作函数,以下列出几个极为常用的:

7.3. 颜色

举例:rgb(171,205,239)

在SASS中,同时使用RGB和HSL来表示颜色,前者是三色光表示法,而后者是色相、饱和度以及亮度。我们通常使用SASS提供的颜色函数来进行操作。当然也可以自定义颜色函数。比起三色光法来说,使用HSL来设计颜色函数更容易达到我们想要的效果。
SASS提供了常用的颜色操作函数,以下列出几个极为常用的:

7.4. 列表

举例:1px solid black

列表是数值的序列,中间用空格或者逗号分隔,列表中可以嵌套列表。
由于分隔符有两种选择,列表嵌套很容易造成不清晰的表述,这里给出一种推荐的写法:在用逗号隔开的列表中加入空格隔开的列表。
另外有一点必须注意,列表必须包含至少一个项目
SASS提供了常用的颜色操作函数,以下列出几个极为常用的:

7.5. 布尔值

只有两种:true和false

布尔值的操作符and、or、not,除此之外还有一些比较运算符会返回布尔值。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注