If you're not using a CSS pre-processor, you're doing it wrong

This post is more than 12 years old.

Posted at 08:00 on 22 February 2012

I’ve been spending quite a bit of time recently experimenting with various JavaScript and CSS frameworks and techniques. What with Node.js being The New Ruby On Rails, and Windows 8 Metro apps going all HTML 5, JavaScript is rapidly maturing from a purely web browser-based scripting language to a powerful, ubiquitous solution. There’s no point in living in denial about it: if you want to keep ahead of the game, JavaScript is the future. Get used to it.

But having said that, HTML/JavaScript/CSS is not without its pain points — and one of the biggest pain points of the lot is CSS.

Here’s the problem. We all know that repetition in code is a bad practice, as are magic constants (bare numbers or strings whose purpose is not clear either from the content or the context). Unfortunately, it’s almost impossible to write vanilla CSS without resorting to copious quantities of both of them. It’s also far too easy to make your selectors too wide-ranging, with the result that fixing one styling issue introduces a dozen more. Vanilla CSS invariably turns into a Big Ball of Mud sooner or later. Usually sooner.

But wouldn’t it be nice if you could have nested class declarations?

#header {  
  h1 {  
    font-size: 26px;  
    font-weight: bold;  
  }  
  p { font-size: 12px;  
    a { text-decoration: none;  
      &:hover { border-width: 1px }  
    }  
  }  
}  

Or if you could have one class declaration inherit from another?

.rounded-corners {
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
}  

#header {
  .rounded-corners;
}

Or even from a parametrised class declaration?

.rounded-corners (@radius: 5px) {
  border-radius: @radius;
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
}  

#header {
  .rounded-corners;
}
#footer {
  .rounded-corners(10px);
}

Or if you could have predefined constants?

@heading-color: #ff6600;  

/* snip */  

h1, h2 {
  color: @heading-color;
}

Or if you could have functions?

@link-color: #ff6600;  
@vlink-color: darken(@link-color, 15%);  
   
a {  
  color: @link-color;  
  &:visited {  
    color: @vlink-color;  
  }  
}  

Well look no more. There are a couple of nifty languages that extend CSS in these very ways, and more. Namely: Less CSS and Sass/SCSS. I’ve been experimenting with Less recently, and I’m now using it on my blog. Sass is fairly similar but has a different syntax. They work simply by compiling into vanilla CSS, in much the same way as CoffeeScript compiles to JavaScript.

Syntactically, Less is a superset of CSS itself, so adoption is generally very easy and the learning curve fairly gentle. Your existing stylesheets should work without modification, though having said that, it is particularly strict about correct syntax, so if you have any typos or browser-specific hacks (which generally only apply to very old browsers such as IE 5.5), you’ll need to get rid of them.

Less is written in JavaScript, and can run either in the browser (all browsers from IE6 upwards are supported), or on the server via Node.js. If you want to run it server-side but don’t want to use Node, there’s a .NET version available called dotLess (conveniently available through NuGet), which also supports features such as CSS minification and caching, and is useful if your business requirements mandate supporting browsers with JavaScript disabled. If you want syntax highlighting in Visual Studio, the Mindscape Web Workbench provides support for both Less and Sass/SCSS, with CoffeeScript support thrown in for good measure.

The bottom line is, if you care about clean code, you need to be using one of these tools. I can not stress this strongly enough: vanilla CSS is a mess, especially on more complex websites, and Less and Sass open up many opportunities to allow you to refactor your style sheets into something more maintainable and robust.