In Defense of Sass

Mar 14, 2022

I've been writing my CSS via Sass for nearly a decade. And, I'll continue to do so even with all the tremendously awesome features making their way into CSS, including nesting.

Why? Because I have found Sass to be an excellent complement to how I approach writing styles, particularly in a team environment. The ability to organize styles into directories such as for design system components but bring them together into a unified stylesheet is really great. So are the built-in methods to cleanly override variables using the !default flag to prevent cascade conflicts or needing to specifically write extra overriding styles. I'm also used to using stylelint within a team to provide extra linting and reinforce style consistency.

I appreciate being able to set constant variables with Sass while still benefiting from the "client-side" nature of CSS custom properties. And the current roadmap for CSS doesn't include things like loops and custom functions, which I also make use of in Sass projects.

Example: Generate Themed Button Classes

To help understand where Sass still fits, let's look at creating a simple themeable button set using Sass.

First, we set up a Sass map to hold our constant color values:

$colors: (
"primary": "hsl(260, 95%, 70%)",
"secondary": "hsl(320, 95%, 60%)"
);

For extended flexibility, I also like to create a list to hold the names of my colors:

$base-colors: ("primary", "secondary");

Then, since these are global values that we will use beyond just our buttons, we'll use a Sass @each loop to output the corresponding CSS custom properties. This uses the $colors map since we need access to both the color name and its value.

:root {
@each $colorName, $colorValue in $colors {
--#{$colorName}: #{$colorValue};
}
}

We'll skip the basic styles for buttons (but you can read my guide to button styling if you're curious), and consider the interesting bit which is creating modifier classes to create the button color variations. This time we use the $base-colors list since we're assigning the custom properties which we reference by the name.

.button {
@each $colorName in $base-colors {
&-#{$colorName} {
--button-background: var(--#{$colorName});
}
}
}

The awesome thing about using custom properties within the Sass loop is that we only have to redefine those cherry-picked values instead of what I did pre-custom properties which was to include a mixin to override rules altogether.

Now to create new button color variations or change the current ones, we only need to update our Sass $colors map and $base-colors list! And this looping idea can be extended to other instances or used to create more generic color utility classes.

In a more extensive project I'd create override-able variables for each color value, and likely break out a specific $buttonColors Sass list variable to better control for button-only colors.

This CodePen demonstrates the full button set created from this technique:

You may also enjoy my 1 minute egghead video demonstrating an alternate theming technique with Sass.