Our BazaarJS series continues. In this article we're going to take a brief (digestive, if you will) pause from the world of Javascript to confront another, equally important, topic: stylesheets. Based on our extensive experience with Sass, we will examine the principle Javascript alternatives available (Less.js and Stylus). Is it worth changing preprocessor? To finish, we will take a look at a range of postprocessing tools that have grown in popularity during 2014.
We know that CSS has its limits. We also know about the unavoidable slowness with which the language is being developed and implemented for browsers. CSS preprocessors have been designed to provide a solution to these problems. They allow developers to avoid writing CSS, and to create stylesheets by using a new meta-language; one that is more powerful and expressive than CSS itself and which can be compiled in simple CSS that can be included in web pages.
So, how long have we all been talking about CSS preprocessors for now? Eight years. Not a short amount of time in our world. Sass, the first project to implement the idea was released as long ago as 2007.
Initially, the project was supported principally by Ruby developers — the hipsters of the epoch, if you will. However, with the passing of time it has slowly and inexorably spread its reach to become a widely recognized tool that can be used in virtually all technology stacks. It has now reigned uncontested, unthreatened by any of its competitors, for at least three years.
2010 saw the release of some interesting Sass alternatives, written — it just so happens — in Javascript. Doing our usual numbers comparison, we can see that these projects are all virtually identical, in terms of the amount of popularity and interest that they have generated:
Sass
- Homepage: http://sass-lang.com
- Created at: September 2007
- Github stars:★ 5.138
Stylus
- Homepage: http://learnboost.github.com/stylus/
- Created at:December 2010
- Github stars:★ 5.173
less.js
- Homepage:http://lesscss.org
- Created at:February 2010
- Github stars:★ 11.617
How are they different from each other?
Well, let's start with the similarities. All three of the languages, albeit with a few qualifications, support:
- Scripting using variables, functions, iterations and conditionals;
- Mixins;
- In-line concatenation of secondary files by means of `@import;
- Nesting of CSS selectors;
- Mathematical functions and functions for managing colours and basic types;
Less.js, unlike Sass and Stylus, does not support:
- Hash structures;
- The ability to write code using a syntax with significant-whitespace;
- Selector inheritance using the
@extend
directive, useful for inheriting CSS rules from a selector without creating duplicate code;
All three projects are well supported by the principal task runners (esp. gulp-stylus, gulp-less and gulp-sass), and are capable of generating source-maps.
Now we come to the chapter on performance. Sass, mainly because of Ruby, is a lot slower than the other preprocessors. The debate, however, does not finish there. In 2012, thanks to the efforts of Hampton Catlin, the creator of Sass, a new project called libsass saw the light of day. Libsass is **a complete restructuring of Sass's C++ motor, one capable of reducing compilation times by orders of magnitude, bringing them below what can be achieved by its Javascript competitors.
In 2014 the Sass and libsass teams reached an agreement to coordinate the release of new additions. A move that quickly led to an almost perfect synchronization of their features: the list of the (few) incompatibilities between the two motors remaining today has been well documented by the Sass Compatibility projected.
As expected, the release of libsass has allowed the language to expand into environments in which a runtime Ruby could not previously be utilized. Today, binding libraries for libsass exist in all of the principal languages, including — obviously — Ruby and Node.js.
Unlike Sass, Less.js and Stylus can carry out the step of precompilation directly on the browser side, without needing to resort to the use of any external tools.
Transpilers and post-processors to the rescue.
To complete our overview of the currently available selection of tools invented to improve the quality of writing of style sheets, we will now take a look at post-processors. PostCSS, a Javascript library made in Twitter, is the umbrella project under which most of these tools have been created. The project allows for simple parsing of CSS files, modification of CSS nodes and generation of new CSS files, complete with source-maps.
Rather than involving the creation of a new metalanguage, the project consists of “augmenting” the results of regular CSS by means of a compilation step.
The most popular examples of this?
- Autoprefixer makes it possible to write CSS code without having to worry about vendor-prefixes. These are added automatically, based on a selection of the population of the browser that it is intended to support, drawing on the latest data available on caniuse.com.
- cssnext, makes it possible to write CSS4 files now, including the advanced behaviours that have already been standardized and those present in the various preprocessors currently available: variables, expressions calc(), semantic media queries, custom selectors, etc. The compilation step reproduces the behaviour described in CSS3 syntax.
Our choice
The Lean Panda team have had long experience with Sass — in fact we have recently “formalized” our way of operating and structuring Sass projects with the release of BEMO.
Well, the analysis we've carried out here hasn't given us any practical reasons that might motivate us to switch to an alternative preprocessor.
In addition to the general “draw” in terms of the features they provide, I feel that I ought to make one further point in favour the Sass's team's approach to the release of new functionality, which is well summarized by 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 that has the least capacity for scripting. For this reason, I would advise someone choosing between which of these languages to try for the first time to concentrate on Sass or Stylus, depending on the environment they're working in (Ruby or Javascript). The projects are very similar to one another, both from the point of view of the functionality that they offer and of the syntax that they deploy; meaning that an eventual switch from one of the systems to the other would not be particularly traumatic.
Returning to Sass, we have had the opportunity to test the libsass engine on a range of projects that have now been in production for several months, and we haven't observed its having any particular problems compared to its older brother. We therefore feel inclined to recommend it, and are awaiting a solution that will let us make use of it inside Sprokets, Rails' asset-pipeline.
The cssnext project is certainly interesting: at least in theory, the idea of being able to write using CSS4 (or its standard) instead of having to invest in alternative metalanguages makes sense, and would offer a way of ensuring that the work put into it doesn't end up “dead” in the space of a few years. In practice, however, despite its many improvements when compared with CSS3, the concept of scripting — so fundamental to frontend projects of medium complexity — continues to be entirely absent.
As regards the management of the browsers' vendor prefixes, Autoprefixer has demonstrated itself to be the best solution available; far superior to mixin, in stile, Compass or Bourbon, which require more maintenance over time. We have used Autoprefixer with great success in conjunction with Sass both within Rails applications (using autoprefixer-rails) and on client-side projects (with gulp-autoprefixer). It now forms part of our standard toolchain.