A good[ish] website
Web development blog, loads of UI and JavaScript topics
Maps are so essential data type of Sass that it’s hard to imagine the time without them. LibSass also supports maps nowadays, so there’s no barriers to use them in day to day programming routines.
Maps in Sass are like associative arrays in PHP, objects in JavaScript, or Hashes in Ruby.
Map facts:
Basic map:
$primary-colors: (
'red': '#ff0000',
'green': '#00ff00',
'blue': '#0000ff'
);
The quotes are not mandatory, they’re only needed if there's spaces or other weird characters. But it just feels nice to have them in there.
Like stated before "keys and values can be any sass object". Here’s all the Sass data types:
1.2, 13, 10px
)"foo", 'bar', baz
)blue
, #04a3f9
, rgba(255, 0, 0, 0.5)
)true
, false
)null
)1.5em 1em 0 2em
, Helvetica, Arial, sans-serif
)(key1: value1, key2: value2)
)This means, for instance, that the value can be a list. In the below map, keys are mapped to two values: hex and RGB:
$primary-colors: (
'red': (
#ff0000,
rbg(255, 0, 0)
),
'green': (
#00ff00,
rbg(0, 255, 0)
),
'blue': (
#0000ff,
rbg(0, 0, 255)
)
);
Nice!
More on that later on in the article.
We’ve got a plethora of functions at our disposal:
Name | Explanation |
---|---|
map-get($map, $key) | Returns the value in a map associated with a given key. |
map-merge($map1, $map2) | Merges two maps together into a new map. |
map-remove($map, $keys…) | Returns a new map with keys removed. |
map-keys($map) | Returns a list of all keys in a map. |
map-values($map) | Returns a list of all values in a map. |
map-has-key($map, $key) | Returns whether a map has a value associated with a given key. |
keywords($args) | Returns the keywords passed to a function that takes variable arguments. |
And the good old @for
, @each
, and @while
loops. Here's a simple loop example using the $primary-colors
map we defined earlier:
@each $color in $primary-colors {
.thing {
content: '#{$color}';
}
}
Now the $color
inside the loop, includes the whole shebang, key and value. To get them separately, define them separately:
@each $color-name, $color-code in $primary-colors {
.color-#{$color-name} {
background: $color-code;
}
}
Here’s a SassMeister demo:
Play with this gist on SassMeister.
z-index
with a @mixin
Here's a nice use case for maps, this is lifted from Hugo Giraudel's blog post.
// Start with a map
$z-layers: (
'cog': 50,
'overlay': 40,
'toc': 30,
'iframe-loader': 25,
'tooltip': 20
) !default;
@function z($layer) {
@if not map-has-key($z-layers, $layer) {
@warn "No layer found for `#{$layer}` in $z-layers map. Property omitted.";
}
@return map-get($z-layers, $layer);
}
That breaks down to:
@if not map-has-key($z-layers, $layer)
— if you gave it a value that isn't in the map, give a friendly warning.@warn
— is the warning :) "...prints the value of a SassScript expression to the standard error output stream", NOTE: @warn prints it to the stream not to the page.@return map-get($z-layers, $layer)
— this returns a value associated with a given key, the $layer
being the key that was passed to the function. This is the only essential line of the mixin, the if statement is only for error handling.Like mentioned before, key or a value can be any Sass object, for instance a list. Let's write a little rgba
background colour mixin. You know how old browsers need an rgb
fallback if rgba
is used. So, here's a map that has both rgba
and rgb
values associated with a single key.
// Map
$primary-colors: (
'red': (
rbga(255, 0, 0, 0.5),
rbg(255, 0, 0)
),
'green': (
rbga(255, 0, 0, 0.5),
rbg(0, 255, 0)
),
'blue': (
rbga(255, 0, 0, 0.5),
rbg(0, 0, 255)
)
);
// Use the map
@mixin colors-w-fallbacks($color) {
@if not map-has-key($primary-colors, $color) {
@warn "No color found for #{$color} in $primary-colors map. Ktnxbye.";
}
@each $color-name, $color-code in $primary-colors {
@if $color-name == $color {
// The rgba value
background: '#{nth($color-code, 2)}';
// And the rgb as a fallback
background: '#{nth($color-code, 1)}';
}
}
}
Surprisingly this won't work:
@mixin colors-w-fallbacks($color) {
background: nth($color, 2);
}
It returns the following error: "List index is 2 but list is only 1 item long for `nth'", cause it won't see the value as a list, but as a variable. More on that in the following demo:
Play with this gist on SassMeister.
First I was like:
// Extract map values to a list
$point-values: ();
@each $point, $value in $breakpoints {
$point-values: append($point-values, unquote(nth($value, 2)), comma);
}
Then I realized there’s a helper method for that:
$list-of-values: map-values($map);
Same goes for keys:
$list-of-keys: map-keys($map);
I think Sass has finally broke into the realm or "fully fledged programming language" when it introduced maps, the last piece of the puzzle so to speak. This post just scratches a surface, maps provide ample opportunities to write DRY and beautiful code.
Comments would go here, but the commenting system isn’t ready yet, sorry.