w3ctech

Sass Maps

对于一位程序员来说,对数组并不会陌生。但对于前端人员(像我这样不算前端的前端)对于数组,只是听过,看过,但不知道如何使用?然而在Sass3.3版本中开始引入一个新的数据类型maps,他长得跟数组非常的相似。但也让我极其的苦逼,因为我不懂数组呀,不知道如何下手开始使用Sass的map功能。

通过阅读一些文章,觉得Sass的map是Sass的强大的特性之一,能帮助我们做好更多的事情,比如说管理媒体查询的断点管理z-index的值管理颜色管理排版等。接下来,我们一起来学习Sass的map

Sass Maps语法

Sass的map常常被称为数据地图,也有人称其为数组,因为他总是以key:value成对的出现,但其更像是一个JSON数据。

{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}

那么Sass的map长得与JSON极其相似:

$map: (
    $key1: value1,
    $key2: value2,
    $key3: value3
)

首先有一个类似于Sass的变量一样,用个$加上命名空间来声明map。后面紧接是一个小括号(),将数据以key:value的形式赋予,其中keyvalue是成对出现,并且每对之间使用逗号(,)分隔,其中最后一组后面没有逗号。

其中键key是用来查找相关联的值value。使用map可以很容易收集键的值和动态插入。我们来回忆一下,在Sass中常用下面的方式定义变量:

$default-color: #fff !default;
$primary-color: #22ae39 !default;

我们使用map可以更好的进行管理:

$color: (
    default: #fff,
    primary: #22ae39
);

如果哪一天,你需要新增加颜色变量值,在map中可以非常随意的添加:

$color: (
    default: #fff,
    primary: #22ae39,
    negative: #d9534f
);

对于Sass的map,还可以让map嵌套map。其实就是map的某一个key当成map,里面可以继续放一对或者多对key:value

$map: (
    key1: value1,
    key2: (
        key-1: value-1,
        key-2: value-2,
    ),
    key3: value3
);

map的嵌套实用性也非常的强,大家可能有碰到过换皮肤的项目,可能每一套皮肤对应的颜色蛮多的,那么使用此功能来管理颜色的变量就非常的有条理性,便于维护与管理。你可以这样使用:

$theme-color: (
    default: (
        bgcolor: #fff,
        text-color: #444,
        link-color: #39f
    ),
    primary:(
        bgcolor: #000,
        text-color:#fff,
        link-color: #93f
    ),
    negative: (
        bgcolor: #f36,
        text-color: #fefefe,
        link-color: #d4e
    )
);

在一些介绍map的老教程中,你会看到这样的方式声明map:

$map: (
    key1 value1,
    key2 value2,
    key3 value3
);

或者:

$map:(
    key1 value1,
    key2 value2,
    key3 (
        key-1 value-1,
        key-2 value-2
    ),
    key4 value4
);

虽然也能编译出CSS,但建议不这样使用。

Sass Maps的函数

前面介绍了使用map来管理变量,但要在Sass中获取变量,或者对map做更多有意义的操作,我们必须借助于map函数功能。在Sass中map自身带了七个函数:

接下来,我们先简单的了解这些函数的具体使用以及所具有的功能。

map-get($map,$key)

map-get($map,$key)函数的作用是根据$key参数,返回$key$map中对应的value值。如果$key不存在$map中,将返回null值。此函数包括两个参数:

  • $map:定义好的map
  • $key:需要遍历的key

来看一个简单的示例,假设定义了一个$social-colorsmap:

$social-colors: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);

假设要获取facebook键值对应的值#3b5998,我们就可以使用map-get()函数来实现:

.btn-dribble{
  color: map-get($social-colors,facebook);
}

编译出来的CSS:

.btn-dribble {
  color: #3b5998; 
}

我们来看另一种情况,假设$social-colors这个map没有$weibo这个key:

.btn-weibo{
  font-size: 12px;
  color: map-get($social-colors,weibo);
}

此时编译出来的是CSS:

.btn-weibo {
  font-size: 12px; 
}

从编译出来的CSS可以得知,如果$key不在$map中,不会编译出CSS,其实在Sass中,map-get($social-colors,weibo)返回了一个null值。但在编译出来的CSS中,你只知道他没有编译出样式,而且在命令终端编译时,也没有任何错误或者警告信息。说实话,你并不知道他为什么编译不出来样式,或者说他已返回了值为null。体验不强,也不好排错。其实哪果我们自定义一个函数,另外加个判断,那就截然不同。

map-has-key($map,$key)

map-has-key($map,$key)函数将返回一个布尔值。当$map中有这个$key,则函数返回true,否则返回false

前面的示例,当$key不在$map中时,使用map-get($map,$key)函数将返回一个null值。但对于开发人员,并看不到任何提示信息。如果使用map-has-key($map,$key)函数就可以改变这一状态。我们来看一个简单的示例。

@if map-has-key($social-colors,facebook){
    .btn-facebook {
        color: map-get($social-colors,facebook);
    }
} @else {
    @warn "No color found for faceboo in $social-colors map. Property ommitted."
}

编译出来:

.btn-fackbook{
    color: #3b5998;
}

上面看到的示例是facebook这个key已存在$social-colors这个map当中。所以能正常编译。如果你手误,将facebook输错了:

@if map-has-key($social-colors,faceboo){
    .btn-facebook {
        color: map-get($social-colors,facebook);
    }
} @else {
    @warn "No color found for faceboo in $social-colors map. Property ommitted."
}

这个时候,你编译出来的CSS代码中,不会有新代码添加,但在命令终端可以看到提示信息:

WARNING: No color found for faceboo in $social-colors map. Property ommitted.
         on line 25 of test.scss

是不是非常的友好。但总觉得这样写是傻傻的,总不可能每获取一个key都写一个@if语句吧。其实不用这么复杂,我们可以自定义一个函数,比如colors():

@function colors($color){
    @if not map-has-key($social-colors,$color){
        @warn "No color found for `#{$color}` in $social-colors map. Property omitted.";
    }
    @return map-get($social-colors,$color);
}

有了这个函数之后,我们就可以这样使用:

.btn-dribble {
    color: colors(dribble);
}
.btn-facebook {
    color: colors(facebook);
}
.btn-github {
    color: colors(github);
}
.btn-google {
    color: colors(google);
}
.btn-twitter {
    color: colors(twitter);
}
.btn-weibo {
    color: colors(weibo);
}

编译出来的CSS:

.btn-dribble {
  color: #ea4c89; 
}

.btn-facebook {
  color: #3b5998; 
}

.btn-github {
  color: #171515; 
}

.btn-google {
  color: #db4437; 
}

.btn-twitter {
  color: #55acee; 
}

同时你不难发现,命令终端提示信息:

WARNING: No color found for `weibo` in $social-colors map. Property omitted.
         on line 13 of test.scss

那是在$social-colors这个map中没有weibo这个key。是不是很有意思。

当然,如果你对Sass的指令熟悉的话,上面编译出来的CSS可以使用@each

@each $social-network,$social-color in $social-colors {
    .btn-#{$social-network} {
        color: colors($social-network);
    }
}

map-keys($map)

map-keys($map)函数将会返回$map中的所有key。这些值赋予给一个变量,那他就是一个列表。如:

map-keys($social-colors);

其返回的值为:

"dribble","facebook","github","google","twitter"

换句话说:

$list: map-keys($social-colors);

相当于:

$list:"dribble","facebook","github","google","twitter";

这个时候,就可以配合Sass的list做很多事情。

上面的示例,可以做通过map-keys($map)来做一个修改:

@function colors($color){
    $names: map-keys($social-colors);
    @if not index($names,$color){
        @warn "Waring: `#{$color} is not a valid color name.`"; 
    }
    @return map-get($social-colors,$color);
}

上面代码中最不同之处,我们使用map-keys$social-colors这个map的所有key取出,并赋予给一个名为$names的列表。然后通过index($names,$color)返回$color$names位置,如果这个位置不存在,将返回提示信息,如果存在将返回正确的值。

.btn-weibo{
    color: colors(weibo);
}

例如,weibo不在$social-colors中,那么不会编译出CSS,而且在命令终端同样会有提示信息:

WARNING: Waring: `weibo is not a valid color name.`
         on line 27 of test.scss

同样,也可以通过@each或者@for遍历出所有值:

@each

@each $name in map-keys($social-colors){
    .btn-#{$name}{
        color: colors($name);
    }
}

@for

@for $i from 1 through length(map-keys($social-colors)){
    .btn-#{nth(map-keys($social-colors),$i)} {
        color: colors(nth(map-keys($social-colors),$i));
    }
}

虽然使用的方法不一样,但最终得到的CSS是一样的:

.btn-dribble {
  color: #ea4c89; 
}

.btn-facebook {
  color: #3b5998; 
}

.btn-github {
  color: #171515; 
}

.btn-google {
  color: #db4437; 
}

.btn-twitter {
  color: #55acee; 
}

map-values($map)

map-values($map)函数类似于map-keys($map)功能,不同的是map-values($map)获取的是$map的所有value值,可以说也将是一个列表。而且,map-values($map)中如果有相同的value也将会全部获取出来。

如前面的示例,使用:

map-values($social-colors)

将会返回:

#ea4c89,#3b5998,#171515,#db4437,#55acee

值与值之前同样用逗号分隔。

map-merge($map1,$map2)

map-merge($map1,$map2)函数是将$map1$map2合并,然后得到一个新的$map。如果你要快速将新的值插入到$map中的话,这种方法是最佳方法。假设我们有两个$map:

$color: (
    text: #f36,
    link: #f63,
    border: #ddd,
    backround: #fff
);
$typo:(
    font-size: 12px,
    line-height: 1.6
);

如果希望将这两个$map合并成一个map,我们只要这样做:

$newmap: map-merge($color,$typo);

将会生成一个新的map:

$newmap:(
    text: #f36,
    link: #f63,
    border: #ddd,
    background: #fff,
    font-size: 12px,
    line-height: 1.6
);

这样你就可以借助map-get()等函数做其他事情了。

不过有一点需要注意,如果$map1$map2中有相同的$key名,那么将$map2中的$key会取代$map1中的:

$color: (
    text: #f36,
    link: #f63,
    border: #ddd,
    backround: #fff
);
$typo:(
    font-size: 12px,
    line-height: 1.6,
    border: #ccc,
    background: #000
);

执行:

$newmap: map-merge($color,$typo);

得到的新map:

$newmap:(
    text: #f36,
    link: #f63,
    font-size: 12px,
    line-height: 1.6,
    border: #ccc,
    background: #000
);

map-remove($map,$key)

map-remove($map,$key)函数是用来删除当前$map中的某一个$key,从而得到一个新的map。其返回的值还是一个mapmap-remove($map,$key)并不能直接从一个map中删除另一个map,仅能通过删除map中的某个key得到新map。如:

$map:map-remove($social-colors,dribble);

返回的是一个新map:

$map:(
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);

如果删除的key并不存在于$map中,那么map-remove()函数返回的新map和以前的map一样。

$map:map-remove($social-colors,weibo);

返回的值:

$map: (
    dribble: #ea4c89,
    facebook: #3b5998,
    github: #171515,
    google: #db4437,
    twitter: #55acee
);

keywords($args)

keywords($args)函数可以说是一个动态创建map的函数。可以通过混合宏或函数的参数变创建map。参数也是成对出现,其中$args变成key(会自动去掉$符号),而$args对应的值就是value

@mixin map($args...){
    @debug keywords($args);
}

@include map(
  $dribble: #ea4c89,
  $facebook: #3b5998,
  $github: #171515,
  $google: #db4437,
  $twitter: #55acee
);

在命令终端可以看到一个输入的@debug信息:

 DEBUG: (dribble: #ea4c89, facebook: #3b5998, github: #171515, google: #db4437, twitter: #55acee)

总结

Sass的map是一个强大的功能。他能帮助大家做很多有兴趣的事情。但map也是个复杂的功能,如果没有理解清楚他的函数功能,发挥的作用会大大打折扣。当然,如果你对Sass熟悉的话,你可以在此基础上自定义一些与map相关的函数,发挥其更大的优势。如果你对Sass的map有相关的使用经验,希望与我们一起分享。

如果对Sass感兴趣的朋友,可以点击这里了解更多的知识

前端圈微信

扫码关注前端圈微信公众号

共收到2条回复

  • 向大漠学习Sass

    回复此楼
  • 大漠老师,我想知道嵌套的map要怎么调用啊

    回复此楼