Sass vs. Less: How To Choose

While there have been numerous comparisons between the two, recently Bootstrap 4, a popular front-end framework, announced it’s transitioning from Less to Sass. This ignited conversation amongst the Zion & Zion developers as to why they would switch CSS preprocessors, and whether we should adopt this change as well. Since “everyone else is doing it” isn’t the best excuse for adopting a new technology, we decided to evaluate the two to understand how they could be applied to our development process.

First of all: what is a CSS preprocessor?

A CSS preprocessor extends CSS by adding features like variables, mixins, and functions not available in vanilla CSS. These features allow for more maintainable and extendable CSS. Less and Sass are by far the two most popular CSS preprocessors.

*It should be noted that Sass has two syntactical options: SCSS and Sass. SCSS is closest to the CSS syntax we’re used to with semicolons and brackets aplenty. Sass does away with these and opts for indented syntax, much like Python.  Any Sass examples will be using the SCSS syntax.

Installation

The first step in using a preprocessor is the installation process. While neither language requires the user to go through a painful process, there are some differences. Sass runs on Ruby while Less runs in Node. For Ruby and Node, you’ll need to compile using command line.

Less can run in the browser, but this is only suggested for development, not production. Sass can run on languages besides Ruby, such as JavaScript, PHP, and Python, through libSass. Another option for compiling to CSS is by using third party tools like Codekit.

Documentation

Learning a new language requires good documentation. While both languages feature extensive documentation that address any possible CSS scenario, I find Less’ documentation more user friendly. Their sticky sidebar displays the user’s positioning on the page, while also allowing them to quickly jump around the documentation.

While Sass’ documentation also features a sidebar, it’s not sticky—so when a user reads past a certain point, they must scroll up to the top or scroll aimlessly just to find the content they’re searching for. However, this is definitely not a make or break for choosing between the two.

Variables

Now for the good stuff!

Preprocessors introduce variables to CSS. Like any language, variables allow us to be able to assign values. For CSS, obvious choices for variables would include colors, fonts, padding, and margin. As with any two languages, syntax differences are expected. Less defines variables with the @ symbol while Sass defines with the $. Less has received some criticism over how imports and media queries also share the @, which may very well confuse a novice coder diving into the CSS realm.

/** SCSS **/
$bg-color: #337ab7;
$color: #fff;

.button {
  background-color: $bg-color;
  color: $color;
  padding: 15px;
}

/** LESS **/
@bg-color: #337ab7;
@color: #fff;

.button {
  background-color: @bg-color;
  color: @color;
  padding: 15px;
}

/** SASS & LESS Output **/
.button {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}

Both languages support variable interpolation. Less carries over the @ with the syntax of @{} while Sass introduces the # with the syntax of #{}. A common use for variable interpolation would be defining paths for background images or font paths.

/** SASS **/
$images: "../images";

nav {
  background: url("#{images}/nav-bg.jpg");
}

/** LESS **/
@images: "../images";

nav {
  background: url("@{images}/nav-bg.jpg");
}

/** LESS and SASS Output **/
nav {
  background: url("../images/nav-bg.jpg");
}

Less allows for lazy loading variables, which means that variables don’t need to be declared before being used.

/** LESS w/ Lazy Loading **/
.button {
  background-color: @bg-color;
  color: @color;
  padding: 15px;
}

@bg-color: #337ab7;
@color: #fff;

/** LESS w/ Lazy Loading Output **/
.button {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}

Lazy loading isn’t supported in Sass. Sass only searches from the current scope and upwards. Variables outside nested selectors are considered global, as with Less. This behavior can be overwritten with the “!global” declaration for nested variables.

Another interesting feature is that hyphens and underscores are interchangeable for variables and will be recognized. I wouldn’t rely heavily on this feature. Stick to one naming convention instead, since most languages are character sensitive.

Nesting

Writing CSS selectors can be a repetitive process. Nesting simplifies this. No longer do you have to write the same line of selectors just to target pseudo classes like :hover and :active. Nesting functions very similarly between the two languages.

/** SCSS and LESS **/
nav {
  background-color: #000;
  width: 100%;
    
    li {
      list-style: none;
      
      a {
        color: #fff;
        text-decoration: none;
      }
   }  
}

/** SCSS and LESS Output **/
nav {
  background-color: #000;
  width: 100%;
}
nav li {
  list-style: none;
}
nav li a {
  color: #fff;
  text-decoration: none;
}

Sass allows you to nest properties, such as font and border. However, this feature could easily be replicated by using shorthand.

/** SCSS Nested Properties **/
h1 {
  font: {
    size: 28px;
    style: italic;
    weight: bold;
  }
}

/** SCSS Nested Properties Output **/
h1 {
  font-size: 28px;
  font-style: italic;
  font-weight: bold;
}

Extend

Extend allows selectors to share properties from a base selector. This will reduce the repetition in your CSS file. A perfect scenario for extends would be if you want all your buttons to have a consistent look to them, but also want them to have different background colors depending on their position on the page.

This will not only simplify your CSS, but also save your HTML from being overloaded with classes. You could condense two classes, one for button styles and one for background color, into one by using an extend.

/** SCSS **/
.button {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}

.button.primary {
  padding: 25px;
}

.success {
  @extend .button;
  background-color: #5cb85c;
}

/** SCSS Output **/
.button, .success {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}

.button.primary, .primary.success {
  padding: 25px;
}

.success {
  background-color: #5cb85c;
}

/** LESS **/
.button {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}

.button.primary {
  padding: 25px;
}

.success {
  &:extend(.button);
    background-color: #5cb85c;
}

/** LESS Output **/
.button,
.success {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}
.button.primary {
  padding: 25px;
}
.success {
  background-color: #5cb85c;
}

Less defines extends by &:extend, while Sass defines extends by @extend. By default, Sass applies extend to every instance of that particular selector. Less doesn’t apply to every instance unless the word “all” is explicitly stated.

/** LESS - EXTEND ALL **/
.button {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}

.button.primary {
  padding: 25px;
}

.success {
  &:extend(.button all);
    background-color: #5cb85c;
}

/** LESS - EXTEND ALL Output **/
.button,
.success {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}
.button.primary,
.success.primary {
  padding: 25px;
}
.success {
  background-color: #5cb85c;
}

Mixins define properties that can be shared among selectors. Mixins become especially useful for bulky CSS3 properties that require several vendor prefixes. Less defines mixins like classes, for example .class, and to include a mixin requires the class to function as a property of the selector.

Sass defines mixins with @mixin. To include a mixin requires “@ include” as a property of the selector. Both languages support arguments to be passed into the mixins.

/** SCSS **/
@mixin button {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}
.primary-button {
  @include button;
  float: right;
  text-align: center;
}

/** LESS **/
.button() {
  background-color: #337ab7;
  color: #fff;
  padding: 15px;
}
.primary-button {
  .button;
  float: right;
  text-align: center;
}

The major difference between the two languages is how they handle mixins. Less mixins can be transformed into functions. Sass separates its functions from its mixins.

Less can return values from its mixins that can be used like a function.

Less also introduces the concept of “mixin guards.” Mixin guards take the place of typical conditional statements. They closely resemble media queries’ syntax. Each condition must have its own mixin. Comparison and logic operators like <, =<,  =, >, >=, “and”, “or,” and “not” are supported within the mixin guards.

The mixins can include a default function, which operates like the else in a conditional statement. When no other condition is met, the default function is applied.

/** LESS **/
.mixin (@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin (@a) {
  color: @a;
}

.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }

/** LESS Output **/

.class1 {
  background-color: black;
  color: #ddd;
  /** less outputs #dddddd **/
}

.class2 {
  background-color: white;
  color: #555;
    /** less outputs #555555 **/
}

Functions

Sass’ answer to functions is what they call control directives and expressions. Sass’ documentation is quick to point out that these directives and expressions are often uncommon in day-to-day styling. In fact, these directives and expressions may be more suitable for larger projects, like front-end frameworks (Bootstrap 4, anyone?).

“If”, “for,” “each,” and “while” are all directives offered by Sass. The “for” directive has two forms: “@ for $var from <start> through <end> “ and “@for $var from <start> to <end>.” The differences between the two is that the “through” method includes the <end> value while the “to” method excludes the <end> value. The for directive also automatically determines where it needs to increment/decrement based on the <start> and <end> values.

/** SCSS **/
$a: #ddd;
$b: #555;

@mixin mixin($color) {
    @if (lightness($color) >= 50%) {
    background-color: black;
    color: $color;
  } @else {
    background-color: white;
    color: $color;
  }
}

.class1 {
  @include mixin($a)
}

.class2 {
  @include mixin($b)
}

/** Doesn't have to be in a mixin **/
/** SCSS **/
.class1 {
  @if (lightness($a) >= 50%) {
    background-color: black;
    color: $color;
  } @else {
    background-color: white;
    color: $color;
  }
}

/** SCSS & LESS Output **/

.class1 {
  background-color: black;
  color: #ddd;
  /** less outputs #dddddd **/
}

.class2 {
  background-color: white;
  color: #555;
    /** less outputs #555555 **/
}

Conclusion

That’s an extensive look at Less and Sass.

The point of this article isn’t to determine which CSS preprocessor is better. It’s important to remember that the type of project you’re working on should dictate what technology should be used. For smaller scale projects, Less or Sass would work perfectly. For larger projects, like front-end frameworks, Sass is probably preferable because of its robust functions.  In addition, you should also consider how you code.

Both languages aim to make your code more efficient and maintainable. Are you likely to use all the available features? Probably not. But you can incorporate those features which will increase your productivity.

Sources:

Less Documentation

Sass Documentation

Bootstrap 4 announcement