BazarJS: CSS pre- (and post-) processors
Our BazarJS series continues with a short (digestive, if you like) break from the Javascript world to tackle an equally important topic: stylesheets. Drawing on our experience with Sass, we'll look at the main Javascript alternatives available (Less.js and Stylus). Is it worth switching preprocessors?
To wrap up, we'll take a look at a set of tools that grew in popularity in 2014 and share a common trait: post-processing.
Our BazarJS series continues with a short (digestive, if you like) break from the Javascript world to tackle an equally important topic: stylesheets. Drawing on our experience with Sass, we'll look at the main Javascript alternatives available (Less.js and Stylus). Is it worth switching preprocessors?
To wrap up, we'll take a look at a set of tools that grew in popularity in 2014 and share a common trait: post-processing.
We all know CSS has its limits, and we also know how slowly the language standard evolves and gets implemented in browsers. The idea of a CSS preprocessor was born precisely from these problems and the desire to fix them: instead of writing CSS, we build stylesheets with a new, more powerful and expressive metalanguage that compiles into plain CSS we can include in our web pages.
Quick question: how long have we been talking about CSS preprocessors? Eight years. That's a long time in our world. Sass, the first project to implement the idea, was released back in 2007.
At first the project was mostly backed by the niche of Ruby developers (the hipsters of the day, if you like), but slowly and inexorably it expanded its reach, becoming a tool known and used on virtually every technology stack, and it reigned unchallenged, without a single competitor, for at least 3 years.
2010 saw the birth of some interesting alternatives, written, as it happens, in Javascript. Running our usual numbers comparison, we can see these are very respectable projects, fully comparable in terms of following and interest generated:
Sass
- Homepage: http://sass-lang.com
- Created: September 2007
- Github stars:★ 5,138
Stylus
- Homepage: http://learnboost.github.com/stylus/
- Created:December 2010
- Github stars:★ 5,173
less.js
- Homepage:http://lesscss.org
- Created:February 2010
- Github stars:★ 11,617
How do they differ?
Well, let's start with the similarities. All three languages, with a few differences, support:
- Scripting with variables, functions, iterators and conditionals;
- Mixins;
- Inline concatenation of secondary files via
@import; - CSS selector nesting;
- Math functions and functions for handling colors and basic types;
Unlike Sass and Stylus, Less.js does not support:
- Hash structures;
- Writing code with a significant-whitespace syntax;
- Selector inheritance via the
@extenddirective, useful for inheriting CSS rules from a selector without duplicating code;
All three projects are widely supported by the main task runners (e.g. gulp-stylus, gulp-less and gulp-sass), and they can all generate source maps.
On to performance. Sass, mainly because of Ruby, is by far the slowest preprocessor. But that's not the end of the story: the efforts of Sass's own creator, Hampton Catlin, led in 2012 to libsass, a complete C++ rewrite of the Sass engine, that cuts compile times by an order of magnitude, bringing them even below its Javascript competitors.
In 2014, the Sass and libsass teams agreed to wait for each other before releasing new language features. The move quickly led to almost complete feature parity: the list of the (few) incompatibilities still remaining between the two engines is well documented in the Sass Compatibility project.
As you would expect, the release of libsass enabled further growth of the language in environments that until then could not afford to introduce a Ruby runtime. Today, there are libsass binding libraries for all the major languages, including, of course, Ruby and Node.js.
Unlike Sass, Less.js and Stylus let you run the precompilation step directly in the browser, so no external tool is needed.
Transpilers and post-processors to the rescue
To complete our overview of the tools currently available for writing better stylesheets, there are the so-called post-processors. PostCSS is the umbrella under which most of these tools were born: a Javascript library made at Twitter that makes it extremely easy to parse CSS files, modify their nodes and output new CSS files, complete with source maps.
So in this case it's not about inventing new metalanguages, but about continuing to write regular CSS and "augmenting" the final output in various ways through a compile step.
The most popular examples?
- Autoprefixer lets you write your CSS without worrying about vendor prefixes. These are added automatically based on the set of browsers you want to support, drawing on the latest data available on caniuse.com.
- cssnext lets you start writing CSS4 files today, with the advanced, already standardized features similar to those found in current preprocessors: variables, expressions with
calc(), semantic media queries, custom selectors, etc. The compile step reproduces the same behavior in CSS3 syntax.
Our choice
Cantiere has long experience with Sass: we recently even "formalized" how we structure a Sass project by releasing BEMO.
Well, our analysis found no practical reason why switching to an alternative preprocessor would be worthwhile.
On top of this substantial feature "parity," I'd give Sass an extra point for the Sass team's approach to releasing new features, nicely summed up in the words of Hugo Giraudel:
What I do like with Sass is its conservative approach to CSS. Sass’s design is based on strong principles: much of the design approach comes naturally out of the core teams’ beliefs that a) adding extra features has a complexity cost that needs to be justified by usefulness and, b) it should be easy to reason about what a given block of styles is doing by looking at that block alone.
Also, Sass has a much sharper attention to detail than other preprocessors. As far as I can tell, the core designers care deeply about supporting every corner-case of CSS compatibility and making sure every general behavior is consistent.
Less.js is currently the system with the weakest scripting capabilities. So if you're choosing a language to try for the first time today, my advice would be to focus on Sass or Stylus, depending on your environment (Ruby or Javascript). The two projects are very similar in both features and syntax, so switching from one to the other later wouldn't be a big deal at all.
Back to Sass: we have been testing the libsass engine on several production projects for months now, without seeing any particular issues or odd behavior compared to its more mature sibling. So we're happy to recommend it, and we're waiting for a solution that lets us use it inside Sprockets, the Rails asset pipeline, too.
The cssnext project is definitely interesting: at least in theory, being able to write in CSS4 (that is, a standard) instead of investing in alternative metalanguages makes sense, and it would offer an extra guarantee that your work won't be "dead" within a few years. In practice, though, despite many improvements over CSS3, the concept of scripting is still completely missing, and it's essential on moderately complex front-end projects.
When it comes to handling browser vendor prefixes, Autoprefixer has proven to be the best solution available, far better than using mixins à la Compass or Bourbon, which require more maintenance over time. We have used Autoprefixer very successfully alongside Sass both in Rails applications (via autoprefixer-rails) and in client-side projects (with gulp-autoprefixer), and it's now part of our go-to toolchain.
That's all... next up? Javascript preprocessors!
Next week we'll keep talking about preprocessors, but in a different context: Javascript. We'll look at the main alternatives out there: CoffeeScript, ECMAScript 6 and TypeScript.