First attempt: repetitive selectors
I recently wrote some Sass code that looked similar to this:
$color-apple: green;
$color-lemon: yellow;
$color-strawberry: red;
.apple-button {
background-color: $color-apple;
}
.strawberry-button {
background-color: $color-strawberry;
}
.lemon-button {
background-color: $color-lemon;
}
// This compiles to:
// .apple-button {
// background-color: green;
// }
//
// .strawberry-button {
// background-color: red;
// }
//
// .lemon-button {
// background-color: yellow;
// }
(No I'm not working on a website for a greengrocers, the fruit theme is just for example purposes! 🍏🍓🍋)
At first glance, it looks OK.
But this code is pretty repetitive. The structure of each selector is the same, except for one word in the name and the colour value.
Also, this pattern doesn't scale efficiently. What if I want to add a blueberry-button
and a grape-button
? I would need to write more nearly identical selectors. What if I want to apply the colour to the font instead of the background instead? I'd have to change the CSS property on multiple lines. This is inefficient!
How could we rewrite this code to be shorter and dryer? That is, to follow the DRY principle of don't repeat yourself? Like this:
Refactor: dry selectors
$fruit-map: (
apple: green,
lemon: yellow,
strawberry: red
);
@each $fruit, $fruit-colour in $fruit-map {
.#{$fruit}-button--dry {
background-color: #{$fruit-colour};
}
}
// This compiles to:
// .apple-button--dry {
// background-color: green;
// }
//
// .lemon-button--dry {
// background-color: yellow;
// }
//
// .strawberry-button--dry {
// background-color: red;
// }
A Sass map is a collection of key-value pairs, much like an object in JavaScript. In this example, $fruit-map
is a map. The fruit name is the key, and the colour is the value.
We can use the Sass each directive to iterate over each pair. We assign the key and value to variables, which we can use to construct our selector using variable interpolation (i.e. this syntax #{$foobar}
).
This code scales well. If we want to generate a new selector, we only need to add a new key-value pair to the map, e.g. blueberry: blue
. If we want to assign the colour to the font instead of the background, we only need to change the CSS property on one line instead of many. Great!
Enhancement: multiple values
But wait, we can take this further! Now each of the fruit-themed buttons also has a different border style. How can we adapt our map to contain multiple values for each key? Try this:
$fruitier-map: (
apple: (green, 1px solid black),
lemon: (yellow, 2px dashed grey),
strawberry: (red, 3px dotted orange)
);
@each $fruit, $fruit-colours in $fruitier-map {
$bg-colour: nth($fruit-colours, 1);
$border-style: nth($fruit-colours, 2);
.#{$fruit}-button--fruitier {
background-color: #{$bg-colour};
border: #{$border-style};
}
}
// This compiles to:
// .apple-button--fruitier {
// background-color: green;
// border: 1px solid black;
// }
//
// .lemon-button--fruitier {
// background-color: yellow;
// border: 2px dashed grey;
// }
//
// .strawberry-button--fruitier {
// background-color: red;
// border: 3px dotted orange;
// }
- Convert the value for each key to a map. Add the colour and the new border value to the map.
- Access each map element using the nth function and assign them to variables.
- Use these variables to create our dynamic CSS selector with interpolation, as before.
The final Sass code is easy to extend and maintain, and also dry. The comprehensive Sass documentation contains more details about these features and many others.
Top comments (8)
Nice! I've been using Sass for awhile, and I didn't know about these features.
Wow! TIL
Me too!
I just used this pattern last week to generate a bunch of "brand classes". It helps a lot with cleaning verbose files, and makes selectors very consistent.
But be aware that debugging a class generated like this can be tricky, even with sourcemaps.
Do not over use it, or maintenance will be hell for anyone not an expert in Sass.
A usually surround these tricks with thorough documentation in the comments.
Amazing, didn't know scss could do that. Thank you!
Enhancement using multiple value great tips.
I REALLY need to incorporate the use of SASS maps more in my projects. So useful!
Great post, Claire! 👍🏻
This is amazing though!