Sass(SCSS): things you may not know


Loop 循环

比较好理解但实用性一般的 @for@while

@each

语法:@each $var in <list or map>

在 SassScript 定义的表达式列表中循环,如:

@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    // ...
  }
}

支持 multiple assignment 多赋值匹配,@each $var1, $var2, ... in <list>

@each $animal, $color, $cursor in (puma, black, default),
                                  (sea-slug, blue, pointer),
                                  (egret, white, move) {
  .#{$animal}-icon {
    border: 2px solid $color;
    cursor: $cursor;
  }
}

map 是 a list of map,因此多赋值匹配也适用。

为了美观也可以把 <list or map> 放在一个变量里,写在循环外边。

$category: (
  'html': $bg-mild-color,
  'css': $heading-color,
  'js': $text-color,
  'other': $em-color
);
.item {
    // ...
    @each $name, $color in $category {
      &.#{$name} {
        background-color: $color;
      }
    }
}

注意:写在 CSS 选择器里的 SassScript string 变量,需要使用 #{} 实现 interpolation 插值

控制指令和表达式

条件语句:

  1. 内置函数 if(boolean, value1, value2)
  2. @if 指令后跟一个 Sass 表达式,若表达式值为 true,则使用大括号中的样式规则。@if 1 + 1 == 2 { border: 1px solid; }
  3. 支持多条件判断,如 @if ... { ... } @else if ... { ... } @else { ... }

循环语句:

  1. @for $var from <start> through <end>, <start> 和 <end> 是返回 integer 整数的 SassScript 表达式。通常是 increment,如果 start 值比 end 大,则采用 decrement。
  2. @for $var from <start> to <end>,与上面语句的区别是,$var 的取值不包含 end
  3. @while … { … }, 可以实现更复杂的循环

$ 开始的变量

最直接使用 SassScript 的情况就是 Sass 的变量。以 $ 开始定义变量名并初始化赋值,然后在任何 property value 里可以使用这个变量(变量值需符合对应的情况)。

局部变量通过 !global 变为全局变量。

.example {
  $width: 5em !global;
  width: $width;
}

@mixin 指令

用来定义可重用的样式规则。

mixin 可以传递参数,可以包含 selector(如 parent reference 选择器 &),可以包含其他 mixin。

因为历史原因,mixin 命名规则可以是 hyphens(dashes) 和 underscores,相互可识别。如定义时为 add-column,使用 add_column 也没问题。反之亦然。

参数

是 SassScript 的变量名,以逗号分隔。

  1. 可以设置默认值,当引用时没有传入该变量,则采用默认值。

     @mixin sexy-border($color, $width: 1in) {
       border: {
         color: $color;
         width: $width;
         style: dashed;
       }
     }
     p { @include sexy-border(blue); }
    
  2. 可以使用 named argument(写明行参和实参的对应关系),这样便于理解和阅读。传参的顺序不再重要

     @mixin colors($text, $background, $border) {
       color: $text;
       background-color: $background;
       border-color: $border;
     }
    
     $value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
     .secondary {
       @include colors($value-map...);
     }
    
  3. 支持传递不确定个数的参数。一些支持多值的 CSS 属性就可以方便使用了。

     @mixin box-shadow($shadows...) {
       -moz-box-shadow: $shadows;
       -webkit-box-shadow: $shadows;
       box-shadow: $shadows;
     }
    
  4. 参数可以从一个 mixin 直接传递给内嵌的子 mixin

用法

定义: @mixin mixinName(arguments) { … }

引用:@include mixinName(variables)

除了用 () 传递变量,还可以用 {} 传递整个内容。

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

编译后:

main #logo {
  background-image: url(/logo.gif);
}

注意:定义在 mixin 里的局部变量对于 @content 代码块是不可见的。

自定义函数 @function

使用该指令定义函数,通过 @return 语句返回值。像 @mixin 一样,函数内可以使用传递进来的参数,也可以使用全局定义的变量。

指向父选择器的 &

& 标志符表示从插入的位置开始,直到最外层的 ancestor selector 组成的组合选择器。

& 标志符除了用在设定同一个元素不同状态(如:&:hover)、元素拥有不同 class (&.custom),还可以用来明确地指出,父选择器应该插入到其他选择器的位置

如下:

a {
  // ...
  body.firefox & { font-weight: normal; }
}

编译后:

body.firefox a {
    font-weight: normal; }

此外,& 可以接一个 suffix 后缀。如果父选择器中不能运用后缀,Sass 会报错。

.sidebar {
  // ...
  &-wrapper {
    // ...
}

编译后:

.sidebar { /* ... */ }
.sidebar-wrapper { /* ... */ }

占位选择器标志 %

% 又称为 @extend-Only Selectors,其定义的样式仅用来继承(必须配合 @extend 指令一起),不直接在 HTML 里使用。

They can be used anywhere a class or id could, and on their own they prevent rulesets from being rendered to CSS

%horizontal-center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.post-list-wrapper, .post-wrapper {
  // ...
  @extend %horizontal-center;
}

编译后:

.post-list-wrapper, .post-wrapper {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

复杂选择器的继承

Class selector 不是唯一可以被 @extend 指令继承的,任何只涉及一个元素的选择器都可以被继承,如:.user[href^="http://"]a:hove

编译结果会把主动继承的 selector 替换成拥有 extend 指令的 selector,然后插入到被继承的复杂选择器中

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

编译后:

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

此外:

  1. 一个 @extend 指令里可以继承多个选择器,以逗号分隔。

    如:@extend .error, .attention;,等价于 @extend .error; @extend .attention;

  2. 支持链式继承。B 继承 A,C 继承 B,则 C 也拥有 A 的样式规则。
  3. 选择器序列,比如后代选择器 .foo .bar 或者立即跟随兄弟选择器 .foo + .bar 目前不支持被继承。但它们内部可使用继承指令。
  4. Sass 支持选择器序列的合并,参看官方文档。原理同蓝字部分,个人觉得应当尽量避免使用,无法预知编译后的 CSS 样式产生的影响。
  5. Sass 目前不支持在 @media 指令模块内应用定义在其外部的 CSS 样式,即定义在媒体查询指令模块外的样式不能使用 @extend 继承。定义在内部的样式可正常继承。

@media

该指令跟纯 CSS 里的表现一致,但是更方便地是可以直接嵌套在 CSS 规则里。这样就不用另外 repeat 选择器再添加基于媒体查询地样式。

If a @media directive appears within a CSS rule, it will be bubbled up to the top level of the stylesheet, putting all the selectors on the way inside the rule.

而且一个 @media 指令还可以嵌套在另一个 @media 指令里。

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

编译后:

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

此外该指令里的 feature names 和 feature values 可以用 SassScript 表达式代替。

除号和属性值分隔符 /

SassScript 中满足这些条件时,分隔符 / 表示除法运算。

  • 值,或它的任何部分,保存在一个变量里
  • 由函数返回
  • 括号包围,但不是 SassScript list 类型变量
  • 值作为另一个数学表达式的一部分

嵌套的属性名

CSS 中有些属性名拥有相同的前缀(类似 namespace,比如 font-sizefont-family)。Sass 允许以属性共同的前缀(比如 font)为“选择器”,内部嵌套 sub-properties。

属性名的前缀 namespace 本身也可以有值

.htmltext {
  stroke: $text-color {
    dasharray: 810;
    dashoffset: 810;
  }
}

编译后:

.htmltext {
  stroke: #363532;
  stroke-dasharray: 810;
  stroke-dashoffset: 810;
}

其他

关于属性值的运算

当属性值由数学运算得到时,操作符前后各保留一个空格

关于注释

跟 JS 一样,用 /**/ 进行多行注释,// 进行单行注释。不同的是多行注释将被保留在编译后的 CSS 文件里,而单行注释不会输出

关于 partial

partial 的概念类似于子模版。如果你想引入一个 SCSS 文件但又不希望这个文件单独编译出来,在文件名开头使用 _ 下划线即可。

之后在引用这个它的文件 import 名字的地方不需要写下划线。比如引入一个 _colors.scss 文件。

@import "colors";

不会有 _colors.css 被编译出来。

注意:同一个目录下,不能同时存在相同名字的 partial 和 a non-partial。比如:_colors.scss 不能和 colors.scss 放在一个目录下.

关于 sass cache

默认地,Sass 缓存编译好的模版和 partials。这样极大地提升了大型 Sass 文件集合的再编译速度。

如果 Sass 模版被细分成单独的文件,并全部使用 @import 引入一个大文件,它将 work best。

在不使用框架的情况下,Sass 作为一个 standalone 的 Ruby 模块,把缓存的模版放在 .sass-cache 目录下。