使用 SassMaps
Sass 的第三个版本给我们带来了新的数据类型,叫做map
。虽然你可以不知道这个名称,但在其他的语言中我们使用过map
,通常就是关联数组。换句话说,Sass的map
就是用关键名匹配对应值的一个数组。
不清楚为什么在CSS中为什么要使用map
(Sass也是CSS),因此这篇文章将告诉你为什么?这个列表虽然不能面面俱到可以随意查找和分享其他用例。
Sass Maps 的语法
在开始之前,让大家在同一个水平上开始讨论这个话题。
Sass的map
使用一个括号,并用冒号将键值与值分隔开来,并且使用逗号将一对键值/值隔开。下面是一个有效的Sass的map
:
$map: (
key: value,
other-key: other-value
);
你需要了解的一些事情:
- 有很多功能可以让你操作Sass的
map
map
中的最后一对键值/值后面的逗号可以省略- 键值必须是唯一的
- 键值/值可以是Sass的任何类型,包括列表和其他的Sass map
是的,键值不一定是字符串,他可以是任何类型。甚至是null
,甚至是map
。前段时间我和Chris Eppstein, Micah Godbolt, Jackie Balzer在Twitter上有一个这方面的讨论。在JavaScript中,不使用字符串做为键值,总感觉不舒服。但在Sass中,这是可以的。
好的,现在你应该准备好了继续往下阅读。
项目的配置
让我们从一个常见的案例开始。当其用到项目的配置中时,Sass的map
是非常完美的。这个想法非常简单,你准备好了键值/值,那么在项目的任何地方你可以通过map-get($map, $key)
来获取他们。
我从我的《Sass中管理响应式断点》一文中取了一个示例:
// _config.scss
$breakpoints: (
small: 767px,
medium: 992px,
large: 1200px
);
// _mixins.scss
@mixin respond-to($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
@media (min-width: #{map-get($breakpoints, $breakpoint)}) {
@content;
}
}
@else {
@warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
+ "Please make sure it is defined in `$breakpoints` map.";
}
}
// _component.scss
.element {
color: hotpink;
@include respond-to(small) {
color: tomato;
}
}
编译出来的CSS:
.element {
color: hotpink;
}
@media (min-width: 767px) {
.element {
color: tomato;
}
}
这样处理很酷。另一个典型的例子是用在颜色上的。对于不同的颜色设置不同的变量也是蛮好的,但当你有几十种颜色的时候,它可能会变得有些凌乱。如果你有一个管理颜色的map
,在一个主题中使用这个map
将是一个不错的选择:
// _config.scss
$colors: (
sexy: #FA6ACC,
glamour: #F02A52,
sky: #09A6E4
);
// _component.scss
.element {
background-color: map-get($colors, sky);
}
最终你会厌倦一遍又一遍使用map-get($colors, ...)
来获取颜色,因此你可以写一个小函数来帮助你减少这样的痛苦:
// _functions.scss
@function color($key) {
@if map-has-key($colors, $key) {
@return map-get($colors, $key);
}
@warn "Unknown `#{$key}` in $colors.";
@return null;
}
// _component.scss
.element {
background-color: color(sky); // #09A6E4
}
有关于这方面的介绍,你可以阅读Erskine Design写的一篇文章《Friendlier colour names with Sass maps》。
让我们来看最后一个关于Sass的map
示例:用map
来配置z-index
。在Sass的项目如何管理z-index
,我想相关介绍最早是来自于Chris Coyier写的一篇文章《如何管理z-index》。你知道怎么写z-index: 999999999;
?那么好,从此以后你不用这么痛苦:
// _config.scss
$z-layers: (
bottomless-pit: -9999,
default: 1,
dropdown: 3000,
overlay: 4000
modal: 4001
);
// _functions.scss
@function z($key) {
@if map-has-key($z-layers, $key) {
@return map-get($z-layers, $key);
}
@warn "Unknown `#{$key}` in $z-layers.";
@return null;
}
// _component.scss
.overlay {
z-index: z(overlay);
}
.element {
z-index: (z(default) + 1);
}
鉴于如何搞定z-index
就可以。我认为这是一件好事,你将所有的索引值放到一个map
中,并慢慢的收集。那么你知道一个应用程序中会有多少个层需要使用,因此你会很容易明白这是怎么一回事。
模块配置
我们继续来聊配置,但让我们聊得更深层次一点,有关于模块/组件的配置。我曾经写过一篇《[使用Sass的map
来配置对象]](http://hugogiraudel.com/2014/05/05/bringing-configuration-objects-to-sass/)》,为什么它会让人感兴趣,多个参数支持单个参数的map
。快速了解一下这个概念:
// _mixins.scss
@mixin module($options: ()) {
$configuration: map-merge((
color: grey,
duration: 0s,
border: null
), $options);
color: map-get($configuration, color);
transition: map-get($configuration, duration);
border: map-get($configuration, border);
}
// _component.scss
.element {
@include module((
color: pink,
duration: .15s
));
}
这种解决方案有一个问题是他引入了混合宏(mixin),这是一个可怕的事情。在现实生活中,一个标签可以用来识别一个人。当读取一个函数/混合宏的标签,我们应该要能确定哪些参数是预期的。通过这种方法,他不是的,因为你必须先阅读默认混合宏的默认参数,你才能知道发生了什么事情。
要解决这个问题,在混合宏中要有一个详细的参数(定义多个参数),然后使用...
来配置一个单一的map
,将前面的示例修改成:
// _mixins.scss
@mixin module($color: grey, $duration: 0s, $border: null) {
color: $color;
transition: $duration;
border: $border;
}
// _component.scss
.element {
@include module((
duration: .15s,
color: pink
)...);
}
在这个案例中,...
扩展了map
中每个键值对应的值。他不仅使混合宏参数更加明确,然而还将混合宏容入到map
中。
这个介绍了如何让map
映射的值插入到混合宏中变成其多个参数。如果我没记错,Python是为数不多的语言,允许你调用一个函数有多个数组。所以在Sass中能做到这一点,真的好强大。
重复的东西
到现在,我们使用map
可以获取关联的值。接下来再整整其他东西,使用Sass的map
让我们不做重复的事情。CSS是一个非常WET(Write Everything Twice)的语言,代码重复是经常可见的。Sass中的的循环,列表和map
非常有用,可以帮助大家不要做重复的事情。
想想字体图标库。字体图标通常是给伪元素:before
的content
传一个硬编码。例如:
.fa-glass:before {
content: "\f000";
}
.fa-music:before {
content: "\f001";
}
.fa-search:before {
content: "\f002";
}
.fa-envelope-o:before {
content: "\f003";
}
.fa-heart:before {
content: "\f004";
}
/* ... */
哇,好烦,好多重复的。如果我们将这些硬编码和类名放到一个map
中:
$icons: (
glass: "\f000",
music: "\f001",
search: "\f002",
envelope-o: "\f003",
heart: "\f004"
);
@each $name, $icon in $icons {
.fa-#{$name}:before {
content: $icon;
}
}
这样做,不是更好吗?尤其是当你有几十个或上百个字体图标的时候。如果你想了解更多这方面的东西,你可以看看Frédéric Perrin 在CodePen上创建的一个小示例。Thoughtbot写了一篇文章《Removing Sass Duplication Using Sass Maps》,使用类似的方法用在背景图片处理上。
CSS Dump
下面是另一个用例(如果我没有记错,这个用例是Micah Godbolt介绍的)。使用Sass的map
来声明一个Sass的列表。你可以看到,使用新功能,Sass的维护者尽量将其往CSS官方的语法靠近。这就是我们为什么在媒体查询中使用一个空的()
列表/map
作为映射值。
因为Sass的map
更像CSS规则的列表,你可能会有一个Sass的混合宏插入Sass的map
中:
// _mixins.scss
@mixin print($declarations) {
@each $property, $value in $declarations {
#{$property}: $value
}
}
// _component.scss
.element {
@include print((
margin: 0 auto,
max-width: 50%,
overflow: hidden
));
}
现在你可能会想这是为什么?为什么不一开始就直接用手编写CSS,而要通过一个混合宏呢?它是关于一个上下文的。当在一个模块中或者其他里面,你通常会设置用一个map
储存一些变量,用来设置组件的默认表现形式,如:
// _component.scss
$configuration: (
padding: 1em,
margin: 0 1em,
color: grey
);
.element {
color: map-get($configuration, color);
padding: map-get($configuration, padding);
margin: map-get($configuration, margin);
&::before {
background-color: map-get($configuration, color);
}
}
而不是通过手动获取每个关键值映射的值,你可以简单的通过css()
混合宏输出map
:
// _component.scss
.element {
@include print($configuration);
&::before {
background-color: map-get($configuration, color);
}
}
编译出的CSS:
.element {
padding: 1em;
margin: 0 1em;
color: grey;
}
.element::before {
background-color: grey;
}
最后思考
正如你所看到的,Sass的map
是一个强大的工具。它不仅让你的代码更有条理,而且还可以帮助你避免代码的冗余和重复。你呢,是怎么使用Sass的 map
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论