Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
So, you want to play 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.

For those who use libsass, while libsass is lacking this as a core feature, there is an add-on library by Lu Nelson sass-list-maps 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 it's 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 is 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 do 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 the keys using a manual naming convention, lets 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 series of 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);
  }
}

Building out frameworks, this is very helpful. 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 pretty 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment