Stop using so many Sass variables.

I used to write Sass that looks like this:

color: $body-text-color
padding: $sidebar-padding

I don't like it any more. Now I love Sass that looks like this:

color: $hot-pink
padding: 20px

The first is an example of abstracting the actual value away from the place you're using it, with a more generic, semantically-named variable in its place.

This approach has many fans, especially when it comes to colours. Here's a simplified example from Sacha Greif's post on the topic:

$blue: #00f
$red: #f00

$text-color: $blue
$link-color: $red

.foo
  color: $text-color

a
  color: $link-color

After doing things like this for a while, I've found that it doesn't make long-term maintenance easier and actually slows down development.

It depends what you mean by “semantic”.

For a variable name to be semantic, it must convey useful meaning. For me as a developer, this is anything but semantic:

.sidebar
  color: $sidebar-text-color

$sidebar-text-color doesn't add any value or meaning that I can't already infer from the selector and property name. It's just repeating information.

To get any meaningful information I need to follow the chain up to one of the two other places that define this value:

// _color_palette.sass
$hot-pink: #bc436c

// _config_variables.sass
$sidebar-text-color: $hot-pink

//_sidebar.sass
color: $sidebar-text-color

That might not sound like much, but multiply it out across your whole project and you get a lot more development overhead.

On the other hand, take this example:

.sidebar
  color: $hot-pink

Immediately there's more useful information available. $hot-pink still abstracts away the meaningless machine-friendly colour code, but adds more meaning for the human developer.

Plus, it's only defined in one place now if I want to see the actual value:

// _color_palette.sass
$hot-pink: #bc436c

//_sidebar.sass
color: $hot-pink

But isn't that a maintenance nightmare?

The common argument goes like this:

What if I want to change my text from hot pink to forest green? I can’t just change $hot-pink’s value to green. That makes no sense!

Agreed. So instead of adding a layer of abstraction that doesn't really do anything to solve that problem, just add the new colour to your palette and update the value where required instead:

// _color_palette.sass
$hot-pink: #bc436c
$forest-green: #0c5c19

// _sidebar.sass
color: $forest-green

Ok? Ok.

But what if I need to update the colour in multiple places?

Update it in multiple places, it's really not that hard.

I can't think of a time when I've wanted to change a value globally across my stylesheet, regardless of where it is used.

I spend the vast majority of my time inside individual modules. Modules are standalone and independent, so I can't think of a case where I'd want to say “change this value wherever it appears in any module”.

Theming

If you generate multiple themes from a single stylesheet or reuse a module across different stylesheets, variables are great! In that case, $sidebar-text-color is genuinely variable, it's not just a global constant with a different name, so I'd totally do this:

// _normal.sass
$sidebar-text-color: $hot-pink

// _christmas.sass
$sidebar-text-color: $red

// _halloween.sass
$sidebar-text-color: $orange

// _sidebar.sass
color: $sidebar-text-color

But how often do you really need to do this? It's pretty rare for me.

Summary

Nicolas Gallagher told us a year ago that content-derived class names aren't always the most useful names for developers, but we're still carrying all that baggage from when we were told that .bold and .red were grounds for expulsion from web development.

Abstracting reusable colours away into human-readable variables, like $hot-pink, is awesome and recommended.

However defining a whole other set of variables with content- or module-derived names…

  • Doesn't make long-term maintenance easier. If I need to change a colour in a module, it's easier to just update a human-readable value right there in the module.

  • Slows down development. Finding or creating a global variable every time I add a color or background property to a ruleset is painful.

If you take this idea beyond colours, you might end up with:

.sidebar
  background: $sidebar-background-color
  color: $sidebar-text-color
  padding: $sidebar-padding-value
  text-align: $sidebar-alignment

And that doesn't look like much fun at all. I'd much rather author and maintain this:

.sidebar
  background: $grey
  color: $hot-pink
  padding: rhythm(1)
  text-align: center