HTML & CSS
Article

5 Great Uses for Sass Maps

By Una Kravets

The Sass map is an awesome tool for organizing your code, minimizing duplication, and making your code base less prone to overall careless errors. They allow us to outline and document our projects in a way that helps with their overall architecture. Maps first came about in Sass 3.3, and have transformed the way developers structure their code. Last year, Hugo wrote a great post about using Sass maps, that I would recommend you also take a look at.

Please note that a Sass sourcemap is not the same thing as a Sass map. Both of these features came out in the same release, and are sometimes confused for each other.

Basic Usage

Maps are surrounded by parenthesis () and are structured in key: value pairs. They are accessed with map-get() and can be nested within each other, allowing for organization of grouped content.

$map-name: (
  key-1: val-1,
  key-2: val-2,
  key-3: val-3
);

So now that we understand the basic structure, let’s dive into five practical strategies for organizing our code that take advantage of maps!

1. Lucid Layering

Let’s start out with some basic map usage. Maps are great for organizing your code, and one place in which this organization is really useful is when dealing with layers of elements in your project (i.e. the z-index).

$layers: (
  modal: 8,
  logo: 7,
  header: 6,
  footer: 5,
  sidebar: 4,
  caption: 3,
  image: 2,
  text: 1
);

Now we can clearly see where all of our elements will lie in relation to each other. Then, we can access this map with the following mixin:

@mixin layer($layer-name) {
  z-index: map-get($layers, $layer-name);
};

And use it as such:

header {
  @include layer('header');
}

2. Color Management

Remember when I said that maps were great for nesting and organizing groups of information? Well let’s put that into practice with color management! Say we have a color palette with specified tints and shades (lighter and darker variations on a base color).

$colors: (
  'red': (
    tint: #f66,
    base: #c00,
    shade: #a00
  ),
  'orange': (
    tint: #f94,
    base: #f50,
    shade: #f12
  ),
  'yellow': (
    tint: #ffa,
    base: #ff0,
    shade: #ff5
  )
);

We can then write a function to grab the colors we want:

@function color($color-name, $tone: base) {
    @return map-get(map-get($colors, $color-name), $tone);
}

This function will read the map for our color and return the base by default. If we input a value for tone, then we get the tint of the color on the map. So background: color('yellow', 'tint') will return the lighter shade. As a (very legible) example,

// .scss
h1 {
  background: color('yellow');
  color: color('red', 'shade');
}

becomes:

h1 {
  background: #ff0;
  color: #a00;
}

You can also begin to label shades by number or any other various naming technique that makes sense to your project.

3. Media Queries

After a bit of surveying on Twitter, I came up with a conclusion on how breakpoint variables should best be named. The old ideology of naming involved device-specific breakpoints such as $phone, $desktop, or $browser. Then, people started realizing that this is a bad strategy – the web is fluid, and one can’t assume what “size” a phone will come in, so they started naming variables small, medium, and large. But these don’t make that much sense either.

Instead, I like the approach of taking the most notable layout change and naming your media queries based on that change. For example, if your layout changes from one column to two, name that media query mq--2-col, and if your major change is the text centering, it can be called $mq--content-center.

An aside: when using variables in the open, I like to prefix them within groups i.e. color--, mq--, or layer--.

Yet, to manage these names even better, we can use a map.

$breakpoints: (
  1-col: 0px,
  left-align-text: 400px,
  2-col: 680px,
  wide-header: 900px
);

Can you see what is going on here? Like an outline, the breakpoints map tells the story of what happens as our page expands. From the smallest point (this is optional, I just included it to prove a point), we have a 1-column, centered-text layout. As it hits 400px, the text aligns left. At 680px, we split into a 2-column layout. At 900px, the header converts into a wide-format iteration. We can see the major layout changes just from reading this map.

And now for a mixin to use the map:

@mixin smaller-than($point-name) {
  $width: map-get($breakpoints, $point-name);
  @media (max-width: $width) {
    @content;
  }
}

@mixin larger-than($point-name) {
  $width: map-get($breakpoints, $point-name);
  @media (min-width: $width) {
    @content;
  }
}

//usage
.heading {
  font-size: 2em;
  @include smaller-than(left-text-align) {
    font-size: 1.5em;
  }
  @include larger-than(2-col) {
    font-size: 3em;
  }
}

4. Accesible Icons

If you are using an icon font (such as IcoMoon) for some simple icons (such as social media icons) on your site, the code for that can be really, really ugly. You can make a quick icon map, mapping the characters for the icons to a class.

$icon-map: (
  dribbble: '\e601',
  facebook: '\e607',
  instagram: '\e60c',
  twitter: '\e602',
  github: '\e603'
);

This way, you can quickly create classes and accessible icons using pseudo-elements by using something like this:

@each $name, $visual in $icon-map {
  .icon--#{$name} {
    font-size: 0;

    &:before {
      font-size: 1rem;
      font-family: 'IcoMoon';
      content: $visual;
    }
  }
}

This generates each icon as a :before pseudo-element, linked to a class name of icon- while making the text of the actual element invisible to the eye, but still legible to screen readers. Meanwhile, the graphic element of the icon remains visible by setting that font-size separately.

So if we have this line of HTML: <div class="icon--facebook">facebook</div>, we will only see the facebook icon mapped to the character \e607.

5. Pattern Libraries

Another great use of maps is for building pattern libraries. One of the biggest complaints developers have against pattern libraries is that they are bulky and full of heavy code, unused by an individual. We don’t want to include any code that we aren’t actually using in order to make our CSS more performant.

Well, maps can fix that! Because maps are just a data structure and don’t output any code until we use map-get to access them, they are perfect for this!

Take animations, for instance. You can structure your animations in a map.

$animations: (
  'fade-in': (
    0%: (
      opacity: 0
    ),
    100%: (
      opacity: 1
    )
  ),
  'fade-flicker': (
    0%: (
      opacity: 1
    ),
    30%: (
      opacity: 0
    ),
    60%: (
      opacity: 1
    ),
    78%: (
      opacity: 0
    ),
    100%: (
      opacity: 1
    )
  )
);

Now unlike keyframes, none of this will output any code until we ask for it to. So currently, there are no keyframes available for us within our project. To mitigate this, let’s make a few mixins and a new map for the animations we will include in our project.

@mixin keyframe-gen($name) {
  @keyframes #{$name} {
    @each $position, $change in map-get($animations, $name) {
      #{$position} {
        @each $prop, $val in $change {
          #{$prop}: #{$val};
        }
      }
    }
  }
};

$included-animations: ();

@mixin animate($name, $duration: 2s, $timing: ease-in) {
  $exists: index($included-animations, '#{$name}');
  @if not $exists {
    @at-root {
      @include keyframe-gen($name);
    }
    $included-animations: append($included-animations, '#{$name}') !global;
  }

  animation: $name $duration $timing;
};

What this is doing is writing out the animation to be included in our project as well as setting that animation to be called on the element. There are no repetitions and our code stays true to a need-to-use output basis. To demonstrate:

.fade-me-in {
  @include animate('fade-in');
}

.also-fade-me-in {
  @include animate('fade-in', 3s);
}

And our only output will be:

@keyframes fade-in {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

.fade-me-in {
  animation: "fade-in" 2s ease-in;
}

.also-fade-me-in {
  animation: "fade-in" 3s ease-in;
}

Maps As Outlines

Clearly, Sass maps are pretty great. They are a data structure which you can use to really help you map out (all of the puns intended) your project and display a summary of its various aspects in a neat and orderly fashion. The biggest advantage is their organizational structure (which acts as an outline for various aspects of your project) and that maps never output any code until called to do so. So try out some of these techniques, and comment with your own ideas for using maps!

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Front-end, once a week, for free.