使用 SassMaps

发布于 2021-03-12 13:16:28 字数 8329 浏览 1361 评论 0

Sass 的第三个版本给我们带来了新的数据类型,叫做map。虽然你可以不知道这个名称,但在其他的语言中我们使用过map,通常就是关联数组。换句话说,Sass的map就是用关键名匹配对应值的一个数组。

不清楚为什么在CSS中为什么要使用map(Sass也是CSS),因此这篇文章将告诉你为什么?这个列表虽然不能面面俱到可以随意查找和分享其他用例。

Sass Maps 的语法

在开始之前,让大家在同一个水平上开始讨论这个话题。

Sass的map使用一个括号,并用冒号将键值与值分隔开来,并且使用逗号将一对键值/值隔开。下面是一个有效的Sass的map

$map: (
  key: value,
  other-key: other-value
);

你需要了解的一些事情:

是的,键值不一定是字符串,他可以是任何类型。甚至是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非常有用,可以帮助大家不要做重复的事情。

想想字体图标库。字体图标通常是给伪元素:beforecontent传一个硬编码。例如:

.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

虐人心

有一天你能到我的心里去,你会看到那里全是你给的伤悲。

0 文章
0 评论
24515 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文