There's a right and a wrong way to do this...

The most common usage of Sass variables is to assign single values for easy implementation and updating of styles in a project. Instead of having multiple instances of color: #f00, having color: $c-red makes changing a shade of red much easier.

The thing is, Sass variables can do so much more than help us easily change colors. They can hold strings of values as well. Whether that be a complex box-shadow value, a list of multiple values to use in a control directive, or a string of text.

For this particular article, I want to take a look at the idea of using variables to store strings of text to be used in the place of CSS selectors. There is a good use case for doing this, and there is also a poor use case.

Let's start with the good

There are two pretty useful use cases for storing text strings as Sass variables, with the intent of using them as CSS selectors.

For our first example, let's say you have to work with an existing CSS framework, or potentially better yet, 3rd-party code that is brought into your website. You know you have a series of overlapping classes that could lead to some late nights of sorting out specificity between your code and theirs.

One very useful way to help differentiate the overlapping classes is to add your own specific prefix to your style library, like so:

.mycss--btn {
  ...
}

.mycss--input {
  ...
}

.mycss--header {
  ...
}

Where mycss--, (please use a better name than that), is how you can easily distinguish your classes from the 3rd-party CSS.

To set this up, and to make updating this name a seamless process, we would use a variable to store our personal selector prefix.

$my-name: mycss--;

.#{$my-name}btn {
  ...
}

.#{$my-name}input {
  ...
}

.#{$my-name}header {
  ...
}

Update: March 8, 2014

So the night after I published this article, Sass 3.3 was released and with it came a handy new feature that can be used with the above example.

With Sass 3.3 we can now create a partial parent selector (our prefix mycss in this case) and use nested & to attached additional partial selectors to the root selector.

So where as above each of the selectors were separated by type, we could instead write our code this way:

.#{$my-name} {

  &btn {...}

  &input {...}

  &header {...}
}

It compiles exactly the same as the previous example, but helps us cut down our code a bit.

To read more about this new method of writing selectors, be sure to check out Stuart Robson's post on "Even Easier BEMing with Sass 3.3"

Both the original method and the updated method may end up being useful to you. The updated method is great if all the rules you want to prefix are in a single file, and can be organized to become children of the prefix selector.

The original method is still useful if you have a one-off instance of needing to apply a prefix, or if it doesn't make sense to reorganize your classes / if you need to apply this prefix across multiple files.

In the end, it's likely that using a combination of both methods is really the ideal solution.

A second example of partial selectors done right with variables is in using Sass variable lists combined with control directives.

For this example, I want to create a family of HTML element and class styles for headings. By that I mean I want to target the HTML element, as well as create a class name to allow heading styling on non-heading elements.

$prefix: txt;

$font-list: (
  h1   $prefix    3em     100,
  h2   $prefix    2.5em   100,
  h3   $prefix    2em     300,
  h4   $prefix    1.75em  300,
  h5   $prefix    1.5em   400,
  h6   $prefix    1.25em  400
);


@each $value in $font-list {

  #{nth($value, 1)},
  .#{nth($value, 2)}-#{nth($value, 1)} {
      font-size: nth($value, 3);
      font-weight: nth($value, 4);
    }

}

And here's the compiled CSS.

h1,
.txt-h1 {
  font-size: 3em;
  font-weight: 100;
}

h2,
.txt-h2 {
  font-size: 2.5em;
  font-weight: 100;
}

h3,
.txt-h3 {
  font-size: 2em;
  font-weight: 300;
}

h4,
.txt-h4 {
  font-size: 1.75em;
  font-weight: 300;
}

h5,
.txt-h5 {
  font-size: 1.5em;
  font-weight: 400;
}

h6,
.txt-h6 {
  font-size: 1.25em;
  font-weight: 400;
}

Here I've created a variable to hold the prefix of txt. I did this in the off-chance that someday I may want to change this to heading or something else that I haven't thought of yet, and editing one value is much easier than six. The rest of the example is to showcase how it could then be incorporated into an additional variable list and control directive. If you're not familiar with control directives, read my article about them.

So those were two moderately useful examples of how to use variables in selectors.

Now here's what you shouldn't do...

$a-base: 'a, a:visited';
$a-hovers: 'a:hover, a:active';


#{$a-base} {
  color: $c-link;
  font-size: 1em;
  text-decoration: none;
}

#{$a-hovers} {
  color: $c-link-hover;
  text-decoratoin: underline;
}

The idea here is that by storing a string of selectors in a variable, you can write some leaner looking code. And you can...sort of.

There are some minor to larger problems with this particular example that I would like to examine.

First of all, unless you know you'll be using this exact selector setup in other parts of your Sass, this doesn't really save us from having to write any code, as it merely just moves our selectors into some variables instead of being associated with the properties that define it.

Now, if you do plan on reusing these selectors, nested in other elements, this can come in handy...to a point.

For example:

#{$a-base} {
  ...
}

#{$a-hovers} {
  ...
}


.sidebar {
  #{$a-base} {
    ...
  }

  #{$a-hovers} {
    ...
  }
}

Being able to reuse our variables in this setup has decreased the amount of code that we need to write a bit, and that's always handy.

However, this setup doesn't really help us out if we need to change individual selectors.

Since they're part of the single Sass variable, if I need to change the a:hover state within the .sidebar but I need to keep the a:active state the same, then I need to do one of the following:

.sidebar {
  #{$a-base} {
    ...
  }

  #{$a-hovers} {
    ...
  }

  a:hover {
    (alternate styling)
  }
}

or

.sidebar {
  #{$a-base} {
    ...
  }

  a:hover {
    (alternate styling)
  }

  a:active {
    (alternate styling)
  }
}

There are two problems with the first example:

  1. I'm double declaring the a:hover styling. This isn't really ideal.
  2. The actual deal-breaker here is that my new a:hover will potentially override some styling for my a:active. Not good...

In the second example, I've had to just forgo my variable selector and re-write the individual selectors to modify their styling. This isn't a crime, as it's what I would have had to do if I weren't using the variable anyway. But, it's an issue here because I'm not reusing my variable, which then makes the variable less useful in general.

Final Thoughts

Using variables to store strings of text and values is amazingly useful. However, while the idea of adding entire selectors to a variable may seem like a good idea at first, I think I've outlined why it has some serious issues.

Regardless if you agree with usefulness of my examples or not, it's undeniable that there's a lot of power to be harnessed with Sass variables. Just be sure you're using it wisely and don't end up making more work for yourself than you need to.