Using SASS maps to manage color schemes
Today was a good day — I finally had the chance to slow down and clean up some code that’s been accumulating for a couple of weeks. I’ve been dying to use Sass maps since I found out about them a few weeks ago, and this was my chance. They were fun to work with, and helped solve some of my lingering Sass issues. Here’s what I did with them, and why and how I did it.
Named variables are the one feature of Sass that I use, without exception, on every single project. Coding and maintenance are miles easier when I can refer to the same color everywhere in my stylesheets as
$light-green instead of juggling around its hex code.
At the same time, I am a bad variable namer. Sass variable names should reflect the role that color (or element with that color) plays in the project; they shouldn’t be the literal definition of that color. Thus,
$heading-underline-color is better than
$light-green. I’ve experimented with this, though, and I always get bogged down in having to figure out and re-figure out what color I’m actually talking about. I’ve employed a strategy like this one, where you begin by creating variables with color-based names and feed those into functionally named variables. While this is easier than using only functional names, it still feels weird to me, so I’ve mostly been sticking with colors.
As I coded my last project, I realized that I was constantly pairing the same two colors together. Any button I made
$light-green, I would make
$light-green-2 on hover. Why didn’t I represent that relationship in the variable names? Thus was born a new naming scheme:
$color for what is usually used as the color for the default state, and
$color-alt for the “alternate” state of that element (focus, hover, visited, etc).
This naming scheme has definitely sped up my work, because I always know what colors to pair together. It’s not a perfect system, though. In addition to the weaknesses inherent to naming Sass variables by superficial characteristics, I run into occasionally wanting to make an element that reverses the roles of
$color-alt, or uses
$color-alt as the base color and a third color (
$color-alt-alt?) as the alt-color. My naming scheme is a slight improvement on one-off variable names, but it’s not a true solution to keeping variables organized relative to each other.
Sass maps to the rescue! They let you store information as key-value pairs, which is a pretty nutty (and awesome) power to have when writing stylesheets.
To begin, I made a Sass map of the colors I’m using in this project. The keys are the default-state colors; the values are the active-state colors1. I don’t have to worry about my naming scheme, since this map codifies the colors’ relationships.
$colors: ( $light-green: $light-green-2, $blue: $light-blue, $light-grey: $light-grey-alt )
Okay, I’ve mapped colors to each other; what now? I incorporated this map into a mixin to generate styled buttons:
@mixin button($bg-color: $light-grey) font-weight: bold padding: .5em ... background-color: $bg-color &:hover, &:focus background-color: map-get($colors, $bg-color)
The original mixin was great, but adding in the Sass map lets me get the job done even more quickly and flexibly. Now, the button’s default color is taken in as an argument; its active color is the value in
$colors associated with its default color2.
With a Sass map, I was able to reduce lines of code, centralize said code, and have more power over styles on a global level. Also, the design language of the project now includes not just individual colors but pairs of colors. As more buttons (and developers) are added to the project, this Sass map guarantees less guesswork and more consistency3.
In short, two thumbs up for Sass maps! I liked the mileage I got out of them today and I’m looking forward to using them more.
Some members of my dev team do mostly backend and don’t know the ins and outs of CSS, let alone Sass. With this in mind, I created a class that extends this mixin with its default value, so that they can add that class to elements without doing any styling. Would it be overkill to make more classes that extend this mixin with different arguments? That’s in a grey area but it’s on my To-do list. ↩
Because it polices what colors go together, this mixin enforces more consistency as opposed to a mixin that takes in two arguments for default and active background colors. Not that I’m not tempted to create that two-argument mixin… ↩