Exploring Maps In Sass 3.3 (Part 1)

Micah Godbolt, Developer
#Mapping | Posted

Sass is already the home to a wide variety of data types. Numbers, strings, lists, colors, and boolean already cover most our needs. But, as our frameworks started to evolve, we realized this list was missing one key tool: the associative array.

Here is a simple list assigned to the variable $objects.

$objects: (carrot, salt, chicken);

Lists are great for capturing multiple pieces of data, but without associated keys, we had no way to assign context, or retrieve data by any means other than an index. So lets look at how we can create these associative arrays (called Maps in Sass).

Here are those same three values, along with keys, assigned to $objects variable.

$objects: (vegetable: carrot, mineral: salt, animal: chicken);

As you can see, this is very similar to the list syntax. You can even perform list functions on it. $objects  is a variable that holds 3 values, each with a unique key. If we want to retrieve the value of salt, we don’t need to know its position, we simply pass in its key along with the name of the map.

$just-a-pinch-of: map-get($objects, mineral); // $just-a-pinch-of == salt

So why is this new data type so valuable? Let’s look at an example.

Organizing Variables

How many times have you seen a list of variables like this?

  1. $primary-nav-top-padding: .2em;
  2. $primary-nav-top-margin: .2em;
  3. $primary-nav-line-height: 1.3;
  4. $secondary-nav-background: white;
  5. $secondary-nav-color: black;

Maps provide us with a means to organize these flat, overflowing lists.

  1. $primary-nav: (
  2. padding-top: .2em,
  3. margin-top: .2em,
  4. line-height: 1.3,
  5. );
  7. $secondary-nav: (
  8. background: white,
  9. color: black,
  10. );

This simple bit of nesting creates some much needed visual separation between each set of variables. It also makes it possible to work with them as a set.

  1. // Sass
  2. @mixin print-styles($map){
  3.  @each $property, $value in $map {
  4.    #{$property}: $value;
  5.  }
  6. }
  8. .primary-nav {
  9.  @include print-styles($primary-nav);
  10. }
  1. // Outputted CSS
  2. .primary-nav {
  3. padding-top: .2em;
  4. margin-top: .2em;
  5. line-height: 1.3;
  6. }

Let's Go Deeper

Need more variation? Maps can hold any data type, including other maps!

  1. // Sass
  2. $primary-nav: (
  3. padding-top: .2em,
  4. margin-top: .2em,
  5. line-height: 1.3,
  6. nav-item: (
  7. color: white,
  8. is-expanded: (
  9. padding-top: 1em,
  10. margin-top: 1em
  11. )
  12. )
  13. );
  15. @mixin print-styles($map, $keys...){
  16.  $i: 1;
  17.  $length: length($keys);
  18.  @while $length >= $i  {
  19.    $map: map-get($map, nth($keys, $i));
  20.    $i: $i + 1;
  21.  }
  23.  @each $property, $value in $map {
  24.    @if type-of($value) != map {
  25.      #{$property}: $value;
  26.    }
  27.  }
  28. }
  30. nav.expanded {
  31.  @include print-styles($primary-nav, nav-item, is-expanded);
  32. }

This print-styles mixin dives into a your map, traversing down each sub-map until you run out of $keys .  At that point it loops through all of the properties, and prints them out one by one.

  1. // Outputted CSS
  2. nav.expanded {
  3.   padding-top: 1em,
  4.   margin-top: 1em,
  5. }

This single variable can hold properties for every variation, or child of the primary navigation without resorting to using $main-navigation-nav-item-is-expanded-is-hovered-margin-top-on-the-blog-page.

In the upcoming week we will look at some more use cases for maps including memorization, enhancing the map-get function and using variables to call other variables.  In the meantime, check out Brad Wade's blog post about how the Department of Energy embraced Sass for their mobile strategy redesign!



Micah Godbolt