Brian Love
Angular + TypeScript Developer in Denver, CO

LESS to SASS

Reading time ~5 minutes

Auf wiedersehen LESS, Hallo SASS! In this post I am going to cover:

  • Why LESS to SASS?
  • How to migrate from LESS to SASS, and a couple of things to note.
  • Using grunt-contrib-sass to compile SASS.
  • Switching to bootrap-sass (until Bootrap 4 is stable).
  • Adding the postcss autoprefixer task to your Grunt tasks to add necessary vendor prefixes to your CSS.
  • And, switching from LESS Hat to the Bourbon SASS mixin library.

Why LESS to SASS?

I’m switching from LESS to SASS, and here’s why:

  • Bootstrap 4 was just announced and is moving to SASS.
  • SASS is more powerful than LESS. Sass has functionality like logical operators, loops, nested media queries, extend, etc.
  • LESS was easy to learn, and it makes for a quick step-up to SASS. So, it seems like the time to get comfortable with SASS is now.

How to go from LESS to SASS

Migrating from LESS to SASS is fairly easy due to the similarity of the syntax. You could run a bunch of regular expressions, but it’s even easier to use the less2sass ruby gem.

Install less2sass:

$ gem install less2sass

Convert your less files to scss:

$ less2sass variables.less _variables.scss

Next, you will want to be sure that you have the SASS Ruby Gem installed. This is required to compile your SASS to CSS. There is a new libsass C library that is being released, which is a high performance library for compiling SASS, but we will be using the Ruby Gem until libsass is stable. You can install it via the command line:

$ sudo gem install sass

Bootstrap 3 SASS

Although Bootstrap 4 is built using SASS, Bootstrap 3 was built using LESS. Thankfully, there is an official port from LESS to SASS.

I’ve added the bootstrap-sass repository as a submodule in my git project:

git submodule add https://github.com/twbs/bootstrap-sass

I then modified my main.scss file to import the Bootstrap SASS file:

@import "/lib/bootstrap-sass/assets/stylesheets/bootstrap"

There are some differences between using Bootstrap with LESS versus the SASS version. These are just a few of the ones that I ran into with my current project.

  • No mixins, such as .hidden() and .show() exist in the bootstrap-sass port.
  • No .img-retina() mixin. However, as we will implement shortly, the Bourbon SASS mixin library includes a @retina-image() mixin.
  • You will need to add the PostCSS Autoprefixer.

Compiling SASS

There are a lot of options when it comes to compiling SASS to CSS, so I will not even try to cover them all here. Instead, I will focus only on using Grunt and the grunt-contrib-sass package.

First, we need to install the grunt-contrib-sass node package. To do so, I have added the following dependency to my package.json file.

{
  "name": "My Application",
  "version": "1.0.0",
  "author": {
    "name": "Brian Love",
    "email": "foo@bar.com"
  },
  "dependencies": {
    "grunt-cli": "latest",
    "grunt-contrib-watch": "latest",
    "grunt-contrib-sass": "latest"
  }
}

Now that I have specified the grunt-contrib-sass package dependency for my application, I can install/update the necessary modules.

$ npm update

Using the grunt-contrib-sass node package we can set up a sass task in our Gruntfile.coffee file. The task compiles the main.scss and ie-8.scss files. Note that I am using the grunt-contrib-sass package. The node-sass node package is a wrapper around the high performance libsass C library, but it is not quite ready for prime time (at the time of this writing).

Here is what my Gruntfile.coffee file looks like:

gruntFunction = (grunt) ->

 gruntConfig =
  sass:
  dist:
  files:
   'css/main.css': 'css/src/main.scss'
   'css/ie-8.css': 'css/src/ie-8.scss'
 watch:
  sass:
   files: ['css/src/*.scss']
   tasks: ['sass']

 grunt.initConfig gruntConfig

 grunt.loadNpmTasks 'grunt-contrib-sass'
 grunt.loadNpmTasks 'grunt-contrib-watch'

 grunt.registerTask 'default', [
  'sass'
 ]

 null

module.exports = gruntFunction

Now, it’s easy to compile my SASS via the default task:

$ grunt

Or, to let the watch task run the sass< task when a .scss file is modified:

$ grunt watch

Adding the PostCSS Autoprefixer

The PostCSS autoprefixer is required when using bootstrap-sass. The autoprefixer will prepend the necessary browser prefixes to your CSS based on the browser list you specify (and based on your business needs). I have decided to target the following browser list:

  • last 2 version
  • 5% in US

  • iOS 7
  • Firefox ESR

This browser list profile will instruct the autoprefixer as to the level of prefixes that are necessary. You would be surprised how few CSS3 properties need to be prefixed still. For example, there is no real reason to prefix box-shadow or border-radius. The best part of the autoprefixer is that it uses the data from caniuse.com, so it’s always up to date. And, now you just write pure W3C CSS3 code without the worry of vendor prefixes!

The autoprefixer is part of the PostCSS library, so we need to specify the package via our package.json file:

{
  "author": {
    "email": "foo@bar.com",
    "name": "Brian Love"
  },
  "dependencies": {
    "autoprefixer-core": "latest",
    "grunt-cli": "latest",
    "grunt-contrib-sass": "latest",
    "grunt-contrib-watch": "latest",
    "grunt-postcss": "latest"
  },
  "name": "My Application",
  "version": "1.0.0"
}

Now we need to update the installed node modules so that the grunt-postcss and autoprefixer-core packages are installed.

$ npm update

Next, we need to update our Gruntfile.coffee file to include a postcss task, which uses the autoprefixer-core processor. The browsers property is an array of values based on the browserslist project.

gruntFunction = (grunt) ->

gruntConfig =
 pkg:
  grunt.file.readJSON 'package.json'

 sass:
  dist:
   files:
    'css/main.css': 'css/src/main.scss'
    'css/ie-8.css': 'css/src/ie-8.scss'

postcss:
 options:
  map: true
  processors: [
   require('autoprefixer-core')(
    browsers: [
     'last 2 versions'
     '> 5% in US'
     'iOS 7'
     'Firefox ESR'
    ]
   )
  ]
 dist:
 src: 'css/*.css'

 watch:
  sass:
   files: ['css/src/*.scss']
   tasks: ['sass', 'postcss']

 grunt.initConfig gruntConfig

 grunt.loadNpmTasks 'grunt-contrib-sass'
 grunt.loadNpmTasks 'grunt-postcss'
 grunt.loadNpmTasks 'grunt-contrib-watch'

 grunt.registerTask 'default', [
  'sass'
  'postcss'
 ]

 null

module.exports = gruntFunction

Running the grunt command again will re-build the main.css file with the autoprefixer processing the CSS for any necessary browser prefixes.

$ grunt

LESS Hat to Bourbon

Bourbon is a nice lightweight mixin library for SASS. So, the last step for me was to switch from LESS Hat to Bourbon. I personally chose to use Bourbon over Compass because I am using Bootstrap and do not need many of the features in Compass.

git submodule add https://github.com/thoughtbot/bourbon

And then we import Bourbon into our main.scss project file:

@import "/lib/bourbon/app/assets/stylesheets/bourbon"

There were some differences between LESS Hat and Bourbon that I will briefly point out. I’m sure there are others, but here are a couple of necessary changes that I ran into.

  • .font-face() - LESS Hat mixin has different arguments than Bourbon. In fact, Bourbon’s @font-face mixin is much better, enabling you to specify the font file formats as a list.
  • .border-top-left-radius() - LESS Hat mixin does not exist in Bourbon, use autoprefixer instead.
  • .border-top-right-radius() - LESS Hat mixin does not exist in Bourbon, use autoprefixer instead.
  • .border-bottom-right-radius() - LESS Hat mixin does not exist in Bourbon, use autoprefixer instead.
  • .border-bottom-left-radius() - LESS Hat mixin does not exist in Bourbon, use autoprefixer instead.
  • $mixin border-right-radius() - Specify the top and bottom right border radius at the same time using Bourbon.

Well, my experience migrating from LESS to SASS was a ton of fun, and I’m really excited about using SASS going forward!

Brian Love

Hi, I'm Brian. I am interested in TypeScript, Angular and Node.js. I'm married to my best friend Bonnie, I live in Denver and I ski (a lot).