Sass @each with multiple variables

CSS预编译的工具已经满大街了,LESS,STYLUS,这里不做“XX比XX强大”的讨论,只要你用得爽,用什么不是用呢。

但是我想说的是,只要你用过SASS,你就再也回不去了。

SASS的强悍功能之一:@each

写过几行ruby的同学都知道each是干嘛用的,就不解释那么多了,直接看代码。

基本用法:

1
2
3
4
5
@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

编译结果:

1
2
3
4
5
6
7
8
.puma-icon {
  background-image: url('/images/puma.png'); }
.sea-slug-icon {
  background-image: url('/images/sea-slug.png'); }
.egret-icon {
  background-image: url('/images/egret.png'); }
.salamander-icon {
  background-image: url('/images/salamander.png'); }

怎样?是不是感动到哭了,知道为什么回不去了么? 因为你终于可以甩掉那烦人、重复、啰哩啰唆的CSS了,切图仔终于也有春天了。

进阶用法:

举个例子,我有一个button样式,button可以有5种颜色,button的icon背景色也有5种颜色,如果写CSS的话,大概有40行,而且基本都是重复代码,一点都不DRY。

button.css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// $green, $pink...都是自定义的颜色
.btn-green {
  background-color: $green;
  border: 1px solid darken($green, 10%);
  i {
    border-right: solid 1px darken($green, 10%);
    background-color: lighten($green, 4%);
  }
}
.btn-pink {
  background-color: $pink;
  border: 1px solid darken($pink, 10%);
  i {
    border-right: solid 1px darken($pink, 10%);
    background-color: lighten($pink, 4%);
  }
}
.btn-dark {
  background-color: $dark;
  border: 1px solid darken($dark, 10%);
  i {
    border-right: solid 1px darken($dark, 10%);
    background-color: lighten($dark, 4%);
  }
}
.btn-red {
  background-color: $red;
  border: 1px solid darken($red, 10%);
  i {
    border-right: solid 1px darken($red, 10%);
    background-color: lighten($red, 4%);
  }
}
.btn-orange {
  background-color: $orange;
  border: 1px solid darken($orange, 10%);
  i {
    border-right: solid 1px darken($orange, 10%);
    background-color: lighten($orange, 4%);
  }
}

这时候,你会想到用@mixin

button.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@mixin text($color) {
  background-color: $color;
  border: 1px solid darken($color, 10%);
}
@mixin icon($color) {
  border-right: solid 1px darken($color, 10%);
  background-color: lighten($color, 4%);
}
.btn-green {
  @include text($green);
  i {
    @include icon($green);
  }
}
.btn-pink {
  ...
}

嗯,这样子确实少打了一些字,但是代码还是很冗余,这时候@each就登场了。

但是问题也来了,SASS是不支持变量里再包个变量的,如:

1
2
3
4
5
6
7
8
9
10
.btn {
  @each $color in green, pink, orange, dark, red {
    &.btn-#{$color} {
      @include text($#{$color}); // 这样写是不合法的
    }
    i {
      @include icon(#{$#{$color}}); // 这样也是不行的
    }
  }
}

终于进入主题了,当你的@each需要多个变量的时候,你就不能像上面那个例子一样用了,这时候你就需要用到list

button.scss
1
2
3
4
5
6
7
8
9
10
.btn {
  $colors-map: (green $green, pink $pink, orange $orange, dark $dark, red $red);
  @each $color in $colors-map {
    &.btn-#{nth($color, 1)} {
      @include text(nth($color, 2));
      i {
        @include icon(nth($color, 2));
      }
    }
  }

看下最终效果吧: