LESS is more

How you can have fun writing CSS by writing LESS

We recently finished up the latest major version of a project at work, a web application that allows our clients to view Facebook Page analytics that we generate and empower them to craft their future social media strategy. The project has seen a couple iterations, but for this one, in an effort to make the whole thing simpler, we reworked most of it from the ground up, including a brand new user interface.

But while CSS is a very powerful tool, this web app was going to require a lot of it, using features from every version of CSS. And while “graceful degradation” was our methodology to some degree, the last version of this product didn’t support any browser except Chrome (because of time constraints) and it was made clear that this time, we would need to support all major browsers. This would mean hundreds of rules, nested rules, exceptions to rules, and fixes for The Browser That Shall Not Be Named.

So in an effort to simplify our CSS develop/test/deploy cycle, we decided to employ LESS, an extended CSS with support for nesting, variables, imports, and expressions.

LESS vs. Sass

I should first mention that we did look at LESS’s main competitor, Sass (sometimes known as SCSS). Sass has many of the same features, like nesting, variables, mix-ins, etc. The main difference between the two is the compiler: Sass’s compiler is a Ruby gem (ew!), and LESS’s compiler is a Node.js package. This might just seem like a personal taste at first, but the fact that LESS’s compiler is Node.js means it’s a version of Javascript, which means it can be run in the browser, which means compilation can happen on the fly, on the client side. This is great for development, although not necessarily a good idea for deployment, but we’ll get into that later.

In the end though, the biggest reason LESS won out for us was that its syntax isn’t a superset of CSS, like Sass. This makes writing LESS feel way more natural, like an improved version of CSS, rather than a whole new language.

Getting started

So what does LESS look like? At its most basic form, it’s just CSS: any valid CSS is also valid LESS.

But this isn’t very interesting, so we’ll improve it to something that makes the switch to LESS a little more worth our while.

Hopefully that code is a lot easier on the eyes. When it’s compiled, it produces the exact same CSS code as above, but rather than having to spell out each level of cascading CSS on each line so it makes sense to browsers, we can nest them in a way which makes sense to developers, with proper scope.

But we can make it even better.

And now you should start to see some of the power behind LESS. By making a border-radius function, we can avoid having to write vendor prefixes more than once. In addition, you’ll notice I wrote the same function twice (overloaded it), so we can choose to call border-radius with one argument if all the radii are the same, or four if they’re different. LESS’s mix-ins do much the same thing: you invoke it in a selector, some LESS takes its place, only mix-ins don’t have arguments.

Another cool thing about LESS is how you can do imports. We used this extensively in our project, by breaking up our style into a bunch of different LESS files and then writing one wrapper file that imported every LESS stylesheet it needed. The main difference here is that in LESS, imports don’t require an additional HTTP request; they’re simply loaded in and compiled (like the way PHP handles includes) and served or output as one big file. This is a nice feature to reduce pageload times, but it comes with a tradeoff, as you don’t necessarily need to load every single style you define for the entire site for every single page. Our technique was to load the styles that were part of the template as one <link>, and the styles that were specific to that page as another. (Potential gotcha: The Browser That Shall Not Be Named’s 4096 selectors “feature”.) Our project, as I look at the code right now, has about twenty LESS files which compile to only six CSS files, so we get the flexibility and organization of working with a lot of files, but the speed of loading a small amount of files.

Developing/testing/deploying

I haven’t even talked about variables, expressions or some of the useful built-in functions, but the official site does a nice job covering those so I won’t. What I’d like to talk about is how we used LESS in our development process and how we deploy it in a fast, low-friction way.

Including a LESS stylesheet in your HTML is pretty simple:

And this is fine for developing and testing. And it’d be fine for deployment, except it’s relying on the client to render the stylesheet correctly, and as we know, relying on users is never a good idea. This method didn’t work at all for some of our LESS sheets in The Browser That Shall Not Be Named, and even if a user is using Chrome, a rogue extension or the user’s disabling of Javascript might prevent this style from rendering. And in the best case, the Javascript renderer is slow because it has to run Javascript and then render the CSS, instead of just loading a static CSS file and rendering that.

So the preferred solution for deployment is compilation to static CSS files, and referencing those from the HTML. LESS has a command-line compiler, which you can install from the Node.js package manager (you can use these commands on a Mac, you’ll need different ones if you’re on Linux, and if you’re on Windows you’ll have to get crazy and use an installer):

And then, to compile a LESS file, you simply run one or both of these commands (shown here for Mac or Linux, but something similar should work on Windows):

The former command produces minified CSS and writes it to a file, while the latter produces inflated CSS.

Speeding up the workflow

So this is good, and it’s relatively simple. Having to install Node.js is sort of a pain, but it’s not that hard and you only need to do it on your development machines. The problem is remembering to do it. The workflow, right now, to push a simple style update, is to edit the LESS file, compile it to the CSS files, add them if necessary, commit, push and deploy; there’s a lot of room for human error.

I wasn’t happy with this, so I set about automating as much of the workflow as I could. I ended up writing a recursive LESS compiler/adder that knew which LESS files needed to be CSS files, and which were just components and so they didn’t need to be compiled separately.

This compiler makes a few assumptions:

  1. That you can run PHP from the command line.
  2. That you have lessc installed and in your PATH.
  3. That your project uses Mercurial (this is fairly easily avoided/changed).
  4. That the directory you run the compiler from is in a directory with two child directories, less and css, which are where your LESS files reside and where your CSS files will be compiled to.
  5. That you (or the user that’s running the script) have permission to write to css.

It’s not the prettiest thing, and I plan to improve it, but for now, it works. If you review the code you’ll notice that it skips files that start with an _ (underscore), so your convention, if you wish to use this compiler, should be that your output files should not start with an underscore, while your includes or helpers should start with an underscore. It also adds files to your Mercurial repository if needed; if you use Git, you should be able to make the change.

To make sure this runs when it’s supposed to, I set up a pre-commit hook in my Mercurial repository to automatically compile everything:

This is a far-from-perfect solution, as it adds time and sometimes compiles unnecessarily, but it’s sort of tough to determine dependencies, so I figured it was good enough for now.

And finally, I wrote a function that lets you pass in the extension-less style you want to load, and depending on if the site is running in production or development mode, load the minified CSS file via <link> or load the LESS file via <link> as well as less.js.

Conclusions

So the final workflow is pretty simple, for me, the developer: make a change to the LESS stylesheet, commit, push, deploy. All of the stuff in the middle is automatic, and until browsers start supporting some form of extended CSS natively (there’s talk of this happening), it’s about as good as it gets.

As a hobby project, I’ve started thinking about developing a LESS compiler in C or C++ which doesn’t depend on Node.js, because a) dependencies are a buzzkill, and b) writing compilers is fun. With a working, fast, non-dependent compiler, you can move the compilation from a commit on the developer’s machine (what we’re at now) to the server and do a just-in-time compilation, with caching, sort of like how minify works now.

Hopefully this has helped a) convince you to check out LESS (or Sass, if you’re into that sort of thing), b) given you an idea of the problems and hurdles you might face, and c) given you an idea on how to overcome them. I know I don’t do many technical blog posts, but I’d like to start doing more of them and I’d like your feedback on what I could do better. Just leave me a comment, send me a tweet, or drop me a line. Thanks for reading, and happy Thanksgiving!


Use Textmate? Here’s a LESS bundle for syntax coloring.



Originally posted on Cleveland, Curveballs and Common Sense on November 24, 2011 at 2:29 AM. Post text content © 2011 Jimmy Sawczuk. All rights reserved.

Comments