Why we moved from Less to Sass

Saatchi & Saatchi's London office is the first to have an in-house Digital branch. We create websites, digital campaigns, email newsletters, flash content and more for a wide range of clients. In the web development team, we're in the unique position of being able to set standards that will hopefully be adopted agency-wide, as Digital arms of Saatchi pop up around the globe.

For this reason, we held a meeting to discuss our technology stack, and decide if there were any current industry standards or better alternatives we could switch to.

Before this meeting, our stack included:

and after:

In this article, I'll write about our switch from Less to Sass.

We initially used Less because it complemented the rest of our stack, and could be implemented without any additional dependencies; it could be installed and compiled using NPM and grunt. Personally, Less always felt like a less-capable alternative to Sass. I had used it when I first discovered CSS pre-processors, as at the time there was a JavaScript compiler that allowed me to try it out without much effort. Although at this time Sass was more feature rich, there was a larger overhead to get started. Less's JS compiler was pretty buggy, especially on mobile, so I decided it might be worth investing the time to get started with Sass. It immediately felt more powerful, and I never looked back.

The way Less has added new features on top of plain CSS appears to be ill-thought-out. It has a habit of creating confusion with its syntax. For example, extends are written like so:

                        
.a:extend(.b) {
    // styles go here
}
                        
                    

It's a strange usage of the colon, which in plain css is used to denote a pseudo state or element:

                        
a:hover {}
a:before {}
                        
                    

Sass extends are much more explicit:

                        
.a {
    @extend .b;
    // styles go here
}
                        
                    

Mixins are also confusing in Less, as they're defined and used with classes:

                        
// definition
.border-radius(@radius: 5px) {
    -webkit-border-radius: @radius;
    -moz-border-radius: @radius;
    border-radius: @radius;
}

// usage
.a {
    .border-radius(10px);
    color: red;
}
                        
                    

In Sass, it's much clearer:

                        
// definition
@mixin border-radius($radius) {
    -webkit-border-radius: $radius;
    -moz-border-radius: $radius;
    -ms-border-radius: $radius;
    border-radius: $radius;
}

// usage
.a {
    @include border-radius(10px);
    color: red;
}
                        
                    

Scanning and reading through Sass files is much easier because its syntax is intuitive and explicit.

In Less, variables are denoted with @, whereas Sass uses $. $ isn't used anywhere else in plain CSS (except for the rarely-used [attribute$=value] selector), so it's safe to use in this new way. @, on the other hand, is used in plain CSS for directives like @import and @media. Sass uses @ to add its own directives, such as @extend, @mixin, and @function, which makes absolute sense.

Overall, Sass has a much clearer syntax that doesn't interfere with or redefine plain CSS, but it's not just the syntax that made us switch; Sass has a more intelligent way handling of lists, loops, and maps, and accepts string interpolation for both properties and values. This leads to more powerful but less verbose functions and mixins that are far easier to understand.

A useful example of string interpolation in Sass is the following, which, at the time of writing, Less was unable to replicate:

                        
$images: "../images/optimized";

body {
    background-image: url(#{$images}/example.png);
}
                        
                    

In this more complex example, adapted from this CodePen, we define two colour palettes. We then use a map function to return palette variations for use in our css. This keeps our project's colours nicely organised and readable:

                        
// set variables
$white: #fff;
$black: #000;

$palettes: (
    maroon: (
        base: #8b2c41, 
        light: #d17f91,
        dark: #41000e,
        contrast: $white
    ),
    green: (
        base: #488329,
        light: #93c478,
        dark: #073e10,
        contrast: $black
    )
);

// palette function
@function palette($palette, $tone: 'base') {
    @return map-get(map-get($palettes, $palette), $tone);
}
  
// usage
.palette-example-1 {
    color: palette(maroon);
}

.palette-example-2 {
    color: palette(green, light);
    background-color: palette(green, contrast);
}

// output
.palette-example-1 {
    color: #8b2c41;
}

.palette-example-2 {
    color: #93c478;
    background-color: #000;
}
                        
                    

The Sass community is full of useful and forward-thinking snippets like this, which helps it feel bigger and more progressive than Less. Its features and syntax just make sense.

We won't be converting old projects over to Sass, we just have a cut-off point where all new projects will use it. We've developed a set of Sass guidelines to help with this transition, which also introduces a mobile-first, component-based front-end architecture and style guide. This will be covered in a future blog post.