Take your Sass skills to the next level with list-maps

Sass 3.3 is out and you should start using Maps.

Using variables in Sass has been a core feature for years now. We have all used them to endless exhaustion, and we have all seen things like this:

// establish a core color
$bravo_gray: #333;

// assign core color to semantic variable
$input-disabled-color:          $bravo_gray;

// Use semantic variable as assigned to additional semantics
$input-disabled-background:     lighten($input-disabled-color, 75%);
$input-disabled-border:         lighten($input-disabled-color, 50%);
$input-disabled-text:           lighten($input-disabled-color, 50%);

This works and it works really well. What we accomplished was a manual name spacing by convention. To use this, we would do the following:

input[disabled] {
  background-color: $input-disabled-background;
  border-color: $input-disabled-border;
  color: $input-disabled-text;
}

The expected CSS output would be:

input[disabled] {
  background-color: #f2f2f2;
  border-color: #b3b3b3;
  color: #b3b3b3; 
} 

We can do better. In Sass 3.3 we were given a new, awesome thing to play with: maps. Maps within lists, to be exact. Sass has had lists for a long time now, but these lists were very flat. Maps give us more dimension to store and retrieve values from a list.

While libsass is lacking this as a core feature, for those who use libsass there is an add-on library by Lu Nelson that you can use.

For the most part, it all works very much the same. There are some key differences in the syntax; there are no colons : between the key:value pairs and there are no trailing commas , after the last item in the array.

The following code examples make use of the Lu Nelson libsass add-on.

Using List-Maps

The first really cool thing with Maps is that you can store key:value pairs (a hash) into a list for later retrieval. Using the primary variable $input as the namespace, we can then nest the extensions in the following way:

$input: (
  disabled-background lighten($input-disabled-color, 75%),
  disabled-border lighten($input-disabled-color, 50%),
  disabled-text lighten($input-disabled-color, 50%)
);

Now that we have all these values stored into an array with keys and values, we can start writing Sass rules that take advantage of this.

In the following example, I used the map-get Sass function to dig into the variable of $input and find its keys. The function map-get takes two arguments, like so: map-get($list, key).

So instead of using the old standard of:

background-color: $input-disabled-background;

I can now use this:

background-color: map-get($input, disabled-background);

All together, I can update the previous input[disabled] selector like so:

input[disabled] {
  background-color: map-get($input, disabled-background);
  border-color: map-get($input, disabled-border);
  color: map-get($input, disabled-text);
}

And this gives us the following CSS output:

input[disabled] {
  background-color: #f2f2f2;
  border-color: #b3b3b3;
  color: #b3b3b3; } 

Nested objects in an array

Looking at the code, there is another pattern emerging. The concept of disabled is repeated. With Maps there is a way to nest these concepts and retrieve the data as well.

The way that Maps work, the only restriction is that each key needs to have a value. Much like JSON, a value may be another set of key:value pairs. An example tree could be the following:

$variable: (
    key (
        key value,
        key value,
        key (
            key value,
            key value
        )
    )
);

Looking at that tree structure and then looking at my previous structure, instead of listing all of the keys using a manual naming convention, let’s use disabled as a name-space, like so:

$input: (
  disabled (
    background lighten($input-disabled-color, 75%),
    border lighten($input-disabled-color, 50%),
    text lighten($input-disabled-color, 50%)
  )
);

To make use of this, Maps allow us to retrieve values from a chain of keys using the map-get-z() function. In the following example you will notice how I am retrieving a series of chained keys delimitated by a comma ,:

background-color: map-get-z($input, disabled, background);

The whole selector would look like this:

input[disabled] {
  background-color: map-get-z($input, disabled, background);
  border-color: map-get-z($input, disabled, border);
  color: map-get-z($input, disabled, text);
}

Using this method we will get the following familiar output CSS:

input[disabled] {
  background-color: #f2f2f2;
  border-color: #b3b3b3;
  color: #b3b3b3; }

List-Maps are smart!

There are many very useful functions for Maps, but one I will illustrate here is the map-has-key() function. In short, this will return a Boolean value if a list has the key you are looking for. The map-has-key() function takes two arguments: the $list and the key. Using this with the @if directive, we can do the following:

@if map-has-key($input, disabled) {
  input[disabled] {
    background-color: map-get-z($input, disabled, background);
    border-color: map-get-z($input, disabled, border);
    color: map-get-z($input, disabled, text);
  }
}

This is very helpful when building out frameworks. We can conditionally respond to available keys within the project, versus throwing the all-too-familiar:

error: unbound variable $input-disabled-background

Conclusion

In short, List-Maps are a welcomed feature when creating larger and larger Sass projects. This feature will give us greater control over how we generate families of variables within a project and how we can apply them more sensibly.


For more Sass resources, check out Dale’s blog and new GitBook, Sass in the Real World.

Next PostPrevious Post

About the Author