Tips to Help You Level Up Your Sass

Writing code is hard. There are many things to be aware of, many pitfalls to avoid, and there’s always room for improvements. Using Sass makes writing CSS a little less hard. Unless you are doing it wrong, in which case it makes CSS even worse.

To avoid that, I want to share a couple of tricks to help you write better Sass.

Use index() Rather than Multiple Equal Assignments

I love reviewing Sass code. I can spend hours digging into Sass code on GitHub repositories. Something I see quite often, especially in Sass frameworks, is the use of multiple equal assignments.

Let’s say you want to check if a value is either initial, inherit, or auto. The usual way of writing this is like this:

@if $value == "initial" or $value == "inherit" or $value == "auto" {
  // Then do something
}

While this does the job fine, not only is it ugly but it is also pretty long to write. What if we simply used the index() function instead? This function…

Returns the position of a value within a list. If the value isn’t found, returns null instead.
Sass reference

Let’s update our example code with this shiny tool:

@if index("initial" "inherit" "auto", $value) {
  // Then do something
}

Some would argue that index() returns a number and not a Boolean, thus shouldn’t be used like this. This is really a matter of choice here. I think this is perfectly fine since we only want to make sure it doesn’t return null (which would be falsy) but if you really want to deal with a Boolean, you can still do:

@if not not index("initial" "inherit" "auto", $value) {
  // Then do something
}

You probably know how to convert a value to a Boolean in JavaScript: !!value. This is the exact same thing, but with not. Appending not before an expression will convert it to a Boolean but will reverse its value. When adding another not, it still is a Boolean but reverses the value again so it keeps the original meaning.

In our case, instead of having a number if it is any of the 3 values, or null if it is not, it is true or false. Again, in this context it doesn’t add anything to the original statement.

If you are worried about all this lowering the sense of the initial expression, you can build a short function for this:

@function is($value, $values) {
  @return not not index($values, $value);
}

And then:

@if is($value, "initial" "inherit" "auto") {
  // Then do something
}

Anyway, my point is: Don’t use multiple equal assignments when you can use the index() function instead.

Use @warn

If there is a feature that is often overlooked by Sass developers, it is the @warn directive. That’s too bad because this is when things start getting fun. @warn gives you the ability to print out messages in the console directly from Sass:

The @warn directive prints the value of a SassScript expression to the standard error output stream. It’s useful for libraries that need to warn users of deprecations or recovering from minor mixin usage mistakes.
Sass reference

This is an awesome tool to warn the developer of:

  • Potential mistakes
  • Deprecations
  • Actions taken by Sass without the developer’s consent
  • What’s going on

The first in that list is the most useful since Sass doesn’t have an @error directive yet. So whenever you make a mixin/function, check the given arguments to make sure they are okay; if they are not, warn the developer (and return a falsy value). For instance:

@function color($color) {
  @if not map-has-key($colors, $color) {
    @warn "No color found for `#{$color}` in `$colors` map.";
  }

  @return map-get($colors, $color);
}

Note: For more information on error handling in Sass, I have written an in-depth article on that topic for Tuts+.

Regarding other use cases for @warn, some libraries use it to deprecate some mixins as they are moving forward; like Bourbon.

@mixin inline-block {
  display: inline-block;
  @warn "inline-block mixin is deprecated and will be removed in the next major version release";
}

Sass-MQ from the Guardian uses it to warn the developer when trying to convert a unitless value to em. Smart move considering this can be ambiguous.

@function mq-px2em($px, $base-font-size: 16px) {
  @if (unitless($px)) {
    @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
    @return mq-px2em($px + 0px); // That may fail.
  } @else if (unit($px) == em) {
      @return $px;
    }
  @return ($px / $base-font-size) * 1em;
}

I could also think of a case where it prints out the configuration of an important mixin when instantiated, kind of a reminder that the app is being loaded, with the given conf.

Use argList for Unknown Number of Arguments

Whenever you build a function or mixin that accepts a list of values of any length, you should probably use an argList rather than a simple list. An argList is the technical data type for what we call variable arguments.

Sometimes it makes sense for a mixin or function to take an unknown number of arguments. For example, a mixin for creating box shadows might take any number of shadows as arguments. For these situations, Sass supports “variable arguments,” which are arguments at the end of a mixin or function declaration that take all leftover arguments and package them up as a list. These arguments look just like normal arguments, but are followed by ....
Sass reference

Why is argList better? From a technical standpoint, it is not. No matter if it is a list or an argList, you will be able to perform the same operations on both, so why bother with this?

In short, because it means something. When using argList, you are explicitly saying this can hold any number of values, there is no restriction, and no check on the length will be performed as long as this argList lives. Meanwhile using a regular list is a just a way to package several values in a single variable. Perhaps you’ll want those several values to be 2. Or 3. Or 4. Any specific number. Like this:

// Function doing something with a key/value pair from a map
// ---
// @param [list] $pair: key/value pair
// ---
@function map-key-value-pair($pair) {
  @if not length($pair) == 2 {
    @warn "`map-key-value-pair` function is expecting a list of 2 items, #{length($pair)} given.";
    @return false;
  }

  // Then do something
}

On the other hand, here is a case where you would want an argList rather than a list:

// Returns the highest value
// ---
// @param [argList] $values: numbers
// ---
@function max($values...) {
  $max: nth($values, 1);

  @for $i from 2 through length($values) {
    $value: nth($values, $i);
    @if $value > $max {
      $max: $value;
    }
  }

  @return $max;
}

In this case, having a list does not make much sense but having an argList gives meaning to the function, even from the signature! So this is pretty much a semantic concern here since there is close to no difference between the two data types.

Use Aliases

This is for those of you building frameworks, grid systems, Compass extensions, and who-knows-what-else with Sass. When you build an API, make it as clear as possible. It doesn’t matter if your function/mixin names are a bit long, as long as they make sense.

But if you don’t want to type the same long function over and over again, make aliases. Then it is the responsibility of the developer to decide whether they would rather use obscure aliases or explicit names.

For instance:

@function get-configuration($option) {
  @return map-get($global-configuration, $option);
}

True, get-configuration() is quite long to type. So make an alias, returning the result of get-configuration():

@function conf($opt) {
  @return get-configuration($opt);
}

There you go. The API is both clear thanks to the original function and simple to use with the alias. Don’t botch your code for the sake of brevity, it isn’t worth it.

Final Thoughts

As you can see, it is the little things that turn the average piece of code into something appealing to work with. Whenever you have time and care about a project, be sure to polish it as much as you can. It’s a great feeling to know you’ve cleaned up and optimized your code as best as you could!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Bruno Seixas

    My need of SASS is yet to be over the top, for now is basically trying to maintain a clean/structured CSS and being able to reuse partials when and where they are needed. I wasnt aware of some of these possibilities =) The @warn seems very handy and can be helpful in a “simple/complex” SASS file ;)

  • Michael

    Really outstanding article — I haven’t been using any of these and I write Sass almost every day.

    • http://www.aatsol.co.za/ Archie Makuwa

      same here… really deep stuff :-D

  • Marc

    First doesn’t seem like a good idea. I would rather write a little more and have the code be legible for whoever picks it up next. No one will understand “not not index(…)”, whereas the if statement was clear at a glance. The other tips are great though!

    • http://hugogiraudel.com/ Hugo Giraudel

      Fair point. I am not a big fan of `not not` either, but I really like the `index()` trick to shorten the code.

      • Pooyan Khosravi

        You can further shorten the code with compiling it then minifinig it :)
        But seriously, boolean algebra is fine. I agree it’s verbose a bit but we should do that rather than using “index of”. I think first point is totally unacceptable, however changing “is” to “isOneOf” makes _only_ last example usable.

        • http://hugogiraudel.com/ Hugo Giraudel

          Fair point again.

  • Gia Thinh

    Amazing argList. Thank you for a great article.

  • Mohd. Mahabubul ALam

    Writing code is hard. There are many things to be aware of, many
    pitfalls to avoid, and there’s always room for improvements. Using Sass
    makes writing CSS a little less hard. Unless you are doing it wrong, in
    which case it makes CSS even worse.