7. @-Rules 与指令 (@-Rules and Directives)

Sass 支持所有的 CSS3 @-Rules,以及 Sass 特有的 “指令”(directives)。这一节会详细解释,更多资料请查看 控制指令 (control directives)混合指令 (mixin directives) 两个部分。

7.1. @import

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

Sass 在当前地址,或 Rack, Rails, Merb 的 Sass 文件地址寻找 Sass 文件,如果需要设定其他地址,可以用 :load_paths 选项,或者在命令行中输入 —load-path 命令。

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

  • 文件拓展名是 .css
  • 文件名以 http:// 开头;
  • 文件名是 url()
  • @import 包含 media queries。 如果不在上述情况内,文件的拓展名是 .scss.sass,则导入成功。没有指定拓展名,Sass 将会试着寻找文件名相同,拓展名为 .scss.sass 的文件并将其导入。
  1. @import "foo.scss";

  1. @import "foo";

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

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

编译为

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

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

  1. @import "rounded-corners", "text-shadow";

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

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

编译为

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

7.1.1. 分音 (Partials)

如果需要导入 SCSS 或者 Sass 文件,但又不希望将其编译为 CSS,只需要在文件名前添加下划线,这样会告诉 Sass 不要编译这些文件,但导入语句中却不需要添加下划线。

例如,将文件命名为 _colors.scss,便不会编译 _colours.css 文件。

  1. @import "colors";

上面的例子,导入的其实是 _colors.scss 文件

注意,不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略。

7.1.2. 嵌套 @import

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

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

  1. .example {
  2. color: red;
  3. }

然后导入到 #main 样式内

  1. #main {
  2. @import "example";
  3. }

将会被编译为

  1. #main .example {
  2. color: red;
  3. }
Directives that are only allowed at the base level of a document, like @mixin or @charset, are not allowed in files that are @imported in a nested context. 这一句不理解

不可以在混合指令 (mixin) 或控制指令 (control directives) 中嵌套 @import

7.2. @media

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

  1. .sidebar {
  2. width: 300px;
  3. @media screen and (orientation: landscape) {
  4. width: 500px;
  5. }
  6. }

编译为

  1. .sidebar {
  2. width: 300px; }
  3. @media screen and (orientation: landscape) {
  4. .sidebar {
  5. width: 500px; } }

@media 的 queries 允许互相嵌套使用,编译时,Sass 自动添加 and

  1. @media screen {
  2. .sidebar {
  3. @media (orientation: landscape) {
  4. width: 500px;
  5. }
  6. }
  7. }

编译为

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

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

  1. $media: screen;
  2. $feature: -webkit-min-device-pixel-ratio;
  3. $value: 1.5;
  4. @media #{$media} and ($feature: $value) {
  5. .sidebar {
  6. width: 500px;
  7. }
  8. }

编译为

  1. @media screen and (-webkit-min-device-pixel-ratio: 1.5) {
  2. .sidebar {
  3. width: 500px; } }

7.3. @extend

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

  1. <div class="error seriousError">
  2. Oh no! You've been hacked!
  3. </div>

样式如下

  1. .error {
  2. border: 1px #f00;
  3. background-color: #fdd;
  4. }
  5. .seriousError {
  6. border-width: 3px;
  7. }

麻烦的是,这样做必须时刻记住使用 .seriousError 时需要参考 .error 的样式,带来了很多不变:智能比如加重维护负担,导致 bug,或者给 HTML 添加无语意的样式。使用 @extend 可以避免上述情况,告诉 Sass 将一个选择器下的所有样式继承给另一个选择器。

  1. .error {
  2. border: 1px #f00;
  3. background-color: #fdd;
  4. }
  5. .seriousError {
  6. @extend .error;
  7. border-width: 3px;
  8. }

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

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

  1. .error.intrusion {
  2. background-image: url("/image/hacked.png");
  3. }

7.3.1. How it Works

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

  1. .error {
  2. border: 1px #f00;
  3. background-color: #fdd;
  4. }
  5. .error.intrusion {
  6. background-image: url("/image/hacked.png");
  7. }
  8. .seriousError {
  9. @extend .error;
  10. border-width: 3px;
  11. }

编译为

  1. .error, .seriousError {
  2. border: 1px #f00;
  3. background-color: #fdd; }
  4. .error.intrusion, .seriousError.intrusion {
  5. background-image: url("/image/hacked.png"); }
  6. .seriousError {
  7. border-width: 3px; }

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

7.3.2. 延伸复杂的选择器 (Extending Complex Selectors)

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

  1. .hoverlink {
  2. @extend a:hover;
  3. }

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

  1. .hoverlink {
  2. @extend a:hover;
  3. }
  4. a:hover {
  5. text-decoration: underline;
  6. }

编译为

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

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

  1. .hoverlink {
  2. @extend a:hover;
  3. }
  4. .comment a.user:hover {
  5. font-weight: bold;
  6. }

编译为

  1. .comment a.user:hover, .comment .user.hoverlink {
  2. font-weight: bold; }

7.3.3. 多重延伸 (Multiple Extends)

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

  1. .error {
  2. border: 1px #f00;
  3. background-color: #fdd;
  4. }
  5. .attention {
  6. font-size: 3em;
  7. background-color: #ff0;
  8. }
  9. .seriousError {
  10. @extend .error;
  11. @extend .attention;
  12. border-width: 3px;
  13. }

编译为

  1. .error, .seriousError {
  2. border: 1px #f00;
  3. background-color: #fdd; }
  4. .attention, .seriousError {
  5. font-size: 3em;
  6. background-color: #ff0; }
  7. .seriousError {
  8. border-width: 3px; }

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

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

7.3.4. 继续延伸 (Chaining Extends)

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

  1. .error {
  2. border: 1px #f00;
  3. background-color: #fdd;
  4. }
  5. .seriousError {
  6. @extend .error;
  7. border-width: 3px;
  8. }
  9. .criticalError {
  10. @extend .seriousError;
  11. position: fixed;
  12. top: 10%;
  13. bottom: 10%;
  14. left: 10%;
  15. right: 10%;
  16. }

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

  1. .error, .seriousError, .criticalError {
  2. border: 1px #f00;
  3. background-color: #fdd; }
  4. .seriousError, .criticalError {
  5. border-width: 3px; }
  6. .criticalError {
  7. position: fixed;
  8. top: 10%;
  9. bottom: 10%;
  10. left: 10%;
  11. right: 10%; }

7.3.5. 选择器列 (Selector Sequences)

暂时不可以将选择器列 (Selector Sequences),比如 .foo .bar.foo + .bar,延伸给其他元素,但是,却可以将其他元素延伸给选择器列:

  1. #fake-links .link {
  2. @extend a;
  3. }
  4. a {
  5. color: blue;
  6. &:hover {
  7. text-decoration: underline;
  8. }
  9. }

编译为

  1. a, #fake-links .link {
  2. color: blue; }
  3. a:hover, #fake-links .link:hover {
  4. text-decoration: underline; }
7.3.5.1. 合并选择器列 (Merging Selector Sequences)

有时会遇到复杂的情况,比如选择器列中的某个元素需要延伸给另一个选择器列,这种情况下,两个选择器列需要合并,比如:

  1. #admin .tabbar a {
  2. font-weight: bold;
  3. }
  4. #demo .overview .fakelink {
  5. @extend a;
  6. }

技术上讲能够生成所有匹配条件的结果,但是这样生成的样式表太复杂了,上面这个简单的例子就可能有 10 种结果。所以,Sass 只会编译输出有用的选择器。

当两个列 (sequence) 合并时,如果没有包含相同的选择器,将生成两个新选择器:第一列出现在第二列之前,或者第二列出现在第一列之前:

  1. #admin .tabbar a {
  2. font-weight: bold;
  3. }
  4. #demo .overview .fakelink {
  5. @extend a;
  6. }

编译为

  1. #admin .tabbar a,
  2. #admin .tabbar #demo .overview .fakelink,
  3. #demo .overview #admin .tabbar .fakelink {
  4. font-weight: bold; }

如果两个列 (sequence) 包含了相同的选择器,相同部分将会合并在一起,其他部分交替输出。在下面的例子里,两个列都包含 #admin,输出结果中它们合并在了一起:

  1. #admin .tabbar a {
  2. font-weight: bold;
  3. }
  4. #admin .overview .fakelink {
  5. @extend a;
  6. }

编译为

  1. #admin .tabbar a,
  2. #admin .tabbar .overview .fakelink,
  3. #admin .overview .tabbar .fakelink {
  4. font-weight: bold; }

7.3.6. @extend-Only 选择器 (@extend-Only Selectors)

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

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

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

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

  1. .notice {
  2. @extend %extreme;
  3. }

编译为

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

7.3.7. !optional 声明 (The !optional Flag)

如果 @extend 失败会收到错误提示,比如,这样写 a.important {@extend .notice},当没有 .notice 选择器时,将会报错,只有 h1.notice 包含 .notice 时也会报错,因为 h1a 冲突,会生成新的选择器。

如果要求 @extend 不生成新选择器,可以通过 !optional 声明达到这个目的,例如:

  1. a.important {
  2. @extend .notice !optional;
  3. }

7.3.8. 在指令中延伸 (@extend in Directives)

在指令中使用 @extend 时(比如在 @media 中)有一些限制:Sass 不可以将 @media 层外的 CSS 规则延伸给指令层内的 CSS,这样会生成大量的无用代码。也就是说,如果在 @media (或者其他 CSS 指令)中使用 @extend,必须延伸给相同指令层中的选择器。

下面的例子是可行的:

  1. @media print {
  2. .error {
  3. border: 1px #f00;
  4. background-color: #fdd;
  5. }
  6. .seriousError {
  7. @extend .error;
  8. border-width: 3px;
  9. }
  10. }

但不可以这样:

  1. .error {
  2. border: 1px #f00;
  3. background-color: #fdd;
  4. }
  5. @media print {
  6. .seriousError {
  7. // INVALID EXTEND: .error is used outside of the "@media print" directive
  8. @extend .error;
  9. border-width: 3px;
  10. }
  11. }

希望有一天,浏览器可以原生支持 @extend 指令,这样就可以在任何指令中使用延伸功能,不再受限制了。

7.4. @at-root

The @at-root directive causes one or more rules to be emitted at the root of the document, rather than being nested beneath their parent selectors. It can either be used with a single inline selector:

  1. .parent {
  2. ...
  3. @at-root .child { ... }
  4. }

Which would produce:

  1. .parent { ... }
  2. .child { ... }

Or it can be used with a block containing multiple selectors:

  1. .parent {
  2. ...
  3. @at-root {
  4. .child1 { ... }
  5. .child2 { ... }
  6. }
  7. .step-child { ... }
  8. }

Which would output the following:

  1. .parent { ... }
  2. .child1 { ... }
  3. .child2 { ... }
  4. .parent .step-child { ... }

7.4.1. @at-root (without: …) and @at-root (with: …)

By default, @at-root just excludes selectors. However, it’s also possible to use @at-root to move outside of nested directives such as @media as well. For example:

  1. @media print {
  2. .page {
  3. width: 8in;
  4. @at-root (without: media) {
  5. color: red;
  6. }
  7. }
  8. }

produces:

  1. @media print {
  2. .page {
  3. width: 8in;
  4. }
  5. }
  6. .page {
  7. color: red;
  8. }

You can use @at-root (without: …) to move outside of any directive. You can also do it with multiple directives separated by a space: @at-root (without: media supports) moves outside of both @media and @supports queries.

There are two special values you can pass to @at-root. “rule” refers to normal CSS rules; @at-root (without: rule) is the same as @at-root with no query. @at-root (without: all) means that the styles should be moved outside of all directives and CSS rules.

If you want to specify which directives or rules to include, rather than listing which ones should be excluded, you can use with instead of without. For example, @at-root (with: rule) will move outside of all directives, but will preserve any CSS rules.

7.5. @debug

The @debug directive prints the value of a SassScript expression to the standard error output stream. It’s useful for debugging Sass files that have complicated SassScript going on. For example:

  1. @debug 10em + 12em;

编译为

  1. Line 1 DEBUG: 22em

7.6. @warn

The @warn directive prints the value of a SassScript expression to the standard error output stream. It’s useful for libraries that need to warn users of deprecations or recovering from minor mixin usage mistakes. There are two major distinctions between @warn and @debug:

  • You can turn warnings off with the —quiet command-line option or the :quiet Sass option.
  • A stylesheet trace will be printed out along with the message so that the user being warned can see where their styles caused the warning. Usage Example:
  1. @mixin adjust-location($x, $y) {
  2. @if unitless($x) {
  3. @warn "Assuming #{$x} to be in pixels";
  4. $x: 1px * $x;
  5. }
  6. @if unitless($y) {
  7. @warn "Assuming #{$y} to be in pixels";
  8. $y: 1px * $y;
  9. }
  10. position: relative; left: $x; top: $y;
  11. }

7.7. @warn

The @error directive throws the value of a SassScript expression as a fatal error, including a nice stack trace. It’s useful for validating arguments to mixins and functions. For example:

  1. @mixin adjust-location($x, $y) {
  2. @if unitless($x) {
  3. @error "$x may not be unitless, was #{$x}.";
  4. }
  5. @if unitless($y) {
  6. @error "$y may not be unitless, was #{$y}.";
  7. }
  8. position: relative; left: $x; top: $y;
  9. }

There is currently no way to catch errors.