Using Sass Maps

Share this article

The third major version of Sass brought a new data type called map. While you might be unfamiliar with this name, we already use maps often in other languages, usually under the names of associative arrays, or hashes. In other words, a Sass map is an array matching keys to values.

It is not always clear why we need maps in CSS (yes, Sass is CSS), hence this article, to give you some hints. This list is obviously not exhaustive so feel free to find and share other use cases.

Syntax for Sass Maps

Before going any further, let’s level everyone up on the topic.

A Sass map uses parentheses as external delimiters, colons to map keys and values, and commas to separate key/value pairs. Here is a valid Sass map:

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

A few things you need to know:

Yes, keys are not necessarily strings; they can be anything. Even null. Even maps. Chris Eppstein, Micah Godbolt, Jackie Balzer, and I had a conversation about this on Twitter a couple of weeks ago. Having kind of a JavaScript background, I don’t feel comfortable with having anything other than a string as a hash key. Anyway, that’s possible in Sass.

Okay, now you should be ready to go!

Project Configuration

Let’s start with a common use case. Maps are perfect when it comes to project configuration. The idea is simple: You associate values to keys, then you access them from anywhere in the project using map-get($map, $key).

I already dug into this in my article on managing responsive breakpoints in Sass. Here’s a quick example:

// _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;
  }
}

Resulting in:

.element {
  color: hotpink;
}

@media (min-width: 767px) {
  .element {
    color: tomato;
  }
}

So this is pretty cool. Another popular use case is colors. Distinct variables for colors are fine, but it can become messy when you have dozens of those. Having a map just for colors, possibly divided into sub-maps for themes, could be a good idea.

// _config.scss
$colors: (
  sexy: #FA6ACC,
  glamour: #F02A52,
  sky: #09A6E4
);

// _component.scss
.element {
  background-color: map-get($colors, sky);
}

Eventually, you’ll get tired of repeating map-get($colors, ...) over and over so you can use a little helper function to ease your pain:

// _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
}

On topic, you might want to read this article by Erskine Design.

Let’s have a look at a last use case for maps as configuration before moving on: z-index layers. I think this first came from Chris Coyier when he wrote about how he manages z-index in Sass projects. You know how you use to write z-index: 999999999? Well, those days are over.

// _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);
}

Given how messed up z-index can be, I think it is a good thing to gather all indexes into a single map, and stick to them. Then you know how many layers the application uses, making it easy to understand what’s going on (and, sooner or later, to debug).

Module Configuration

We will stick to configuration but let’s get deeper into application levels, tackling module/component configuration. I already wrote about using Sass maps as configuration objects and why it can be interesting to ditch the multi-arguments signature in favor of a single map parameter. Quick proof of concept:

// _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
  ));
}

One problem with this solution is it makes the mixin signature terribly generic. In real life, a signature is a way to identify a person. When reading a function/mixin signature, we should be able to identify what arguments are expected. With this approach, it is not, because you have to read the default options in the mixin to know what’s going on.

To work around the problem, define the mixin with a verbose signature (regular multiple arguments) then include it with a single configuration map using .... Let’s rewrite our previous example:

// _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
  )...);
}

In this case, ... expands the map of values so that each pair is treated as a keyword argument. Not only does it make the mixin signature more explicit, but it also ditches all the map-merging stuff previously required at the top of the mixin’s core.

So this is how you could use Sass maps to configure your mixins that ask for multiple arguments. If I’m not mistaken, Python is one of the few (well-known) languages that allows you to call a function with a multi-dimensional array while it asks for multiple arguments. So the fact Sass is able to do so is pretty awesome.

Repetitive Stuff

Until now, we have used maps in order to get the value associated to a specific key. A whole other kind of use case for Sass maps is avoiding repetitive stuff. CSS being a very WET (Write Everything Twice) language, code repetitions are common. This is where having a loop and a list/map helps a lot in making code DRY (Don’t Repeat Yourself).

Think of icon fonts. An icon font is usually a collection of encoded characters passed via the content property of the :before pseudo-element. For instance:

.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";
}

/* ... */

Wow. Very repetition. Much WET. What if instead we mapped class names to the encoded characters?

$icons: (
  glass: "\f000",
  music: "\f001",
  search: "\f002",
  envelope-o: "\f003",
  heart: "\f004"
);

@each $name, $icon in $icons {
  .fa-#{$name}:before {
    content: $icon;
  }
}

Better, isn’t it? Especially when you have dozens and dozens of icons in the font. If you want to push things further, Frédéric Perrin created a cool little demo using this very idea on CodePen. There is also an article from ThoughtBot using the same approach with background images.

CSS Dump

Here’s another use case (first introduced by Micah Godbolt, if I’m not mistaken). We will use a Sass map as a list of CSS declarations. You see, Sass maintainers do their best to stick as close as possible to official CSS syntax when implementing new features. This is why they decided to use () for lists/maps (used in media queries) and the colon as a mapping operator (used in any declaration).

Because Sass maps look like lists of CSS rules, you could possibly have a mixin dumping the content of a 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
  ));
}

Now you might be thining Why? Why not just write the CSS manually from the start rather than passing it through a mixin? It is all about context. When dealing with a module or something, you usually have a map storing a couple of variables laying down how the component should behave. For instance:

// _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);
  }
}

Rather than manually getting each value from the key, you could simply print the map with the css() mixin;

// _component.scss
.element {
  @include print($configuration);

  &::before {
    background-color: map-get($configuration, color);
  }
}

Resulting in:

.element {
  padding: 1em;
  margin: 0 1em;
  color: grey;
}

.element::before {
  background-color: grey;
}

It’s not much, but it’s something!

Final Thoughts

As you can see, the Sass maps feature is a powerful tool. Not only does it make the code more structured, but it also helps you avoid some code bloat and repetition. What about you, how do you use Sass maps?

Frequently Asked Questions (FAQs) about Using Sass Maps

What are the key differences between Sass Maps and other Sass data types?

Sass Maps are a unique data type in Sass that allows you to store multiple values in a single variable. Unlike other Sass data types like numbers, strings, colors, and lists, Maps are more like associative arrays in other programming languages. They store key-value pairs where each key is associated with a value. This makes it easier to manage and manipulate complex data structures in your stylesheets.

How can I create a Sass Map?

Creating a Sass Map is quite straightforward. You can create a Map by using parentheses () and separating the keys and values with a colon. For example, $map: (key1: value1, key2: value2). You can also nest Maps within other Maps to create more complex data structures.

How can I access values in a Sass Map?

You can access values in a Sass Map using the map-get() function. This function takes two arguments: the Map and the key. For example, map-get($map, key1) would return value1.

Can I modify values in a Sass Map?

Yes, you can modify values in a Sass Map using the map-merge() function. This function takes two Maps as arguments and returns a new Map that combines the key-value pairs of both Maps. If both Maps have the same key, the second Map’s value will overwrite the first Map’s value.

How can I loop through a Sass Map?

You can loop through a Sass Map using the @each directive. This directive takes a variable and a Map, and for each key-value pair in the Map, it assigns the key and value to the variable and executes the block of code. For example, @each $key, $value in $map { … }.

What are the benefits of using Sass Maps?

Sass Maps offer several benefits. They allow you to store complex data structures in a single variable, making your code more organized and easier to manage. They also provide powerful functions for manipulating Maps, such as map-get(), map-merge(), and map-remove(). Furthermore, you can use the @each directive to loop through a Map, which can be very useful for generating repetitive CSS.

Can I use Sass Maps with other Sass features?

Yes, you can use Sass Maps with other Sass features like mixins, functions, and control directives. For example, you can create a mixin that takes a Map as an argument and generates CSS based on the Map’s key-value pairs.

Are there any limitations to using Sass Maps?

While Sass Maps are very powerful, they do have some limitations. For example, you cannot use a Map as a CSS value. Also, Maps are not fully supported in all versions of Sass, so you may encounter compatibility issues in older versions.

How can I debug a Sass Map?

You can debug a Sass Map using the @debug directive. This directive prints the value of a Sass expression to the console, which can be very helpful for debugging. For example, @debug map-get($map, key1) would print the value of key1 to the console.

Where can I learn more about Sass Maps?

There are many resources available online for learning more about Sass Maps. The official Sass documentation is a great place to start. It provides a comprehensive overview of Maps and other Sass features. Other resources include online tutorials, blog posts, and video courses.

Kitty GiraudelKitty Giraudel
View Author

Non-binary trans accessibility & diversity advocate, frontend developer, author. Real life cat. She/they.

sasssass maps
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week