Write Better CSS with Less

LessI have a confession: I think parts of CSS suck. It’s repetitive, tedious, and … well, kind of dumb.

I for one find it quite counter-intuitive to specify descendants’ styles like this:

#banner { color: white; background: black; }
#banner a { color: yellow; }
#banner p { margin: 0; }
#banner ...
#banner ...
#banner ...

… and on, and on, and on. Instead, this makes way more sense to me:

#banner {
  color: white;
  background: black;
    a { color: yellow; }
    p { margin: 0em; }
    ...
}

And how about variables? They’d be cool:

@logo = #457301;

h3 { color: @logo; }
#sale { border: 1px solid @logo; }
.alert { background: @logo; }

Are you with me? Well, Less promises to make these daydreams and more a happy reality. You’d write a style sheet using the Less syntax, which is exceptionally easy to pick up — it’s just CSS with some added CSS-like extras. You then use the Less Ruby gem to convert it into regular CSS — run it on the command line, or incorporate it into an app.

Less permits you to use variables and nested selectors, as seen above, but also offers a way to include classes within classes, and some simple math operators. Sweet! Let’s put Less through its paces and see how it copes with a simpler style sheet.

Let’s say I’m making a style sheet for a reasonably common grid structure, like so:

Grid: three at the top, four in the centre, six at the bottom

Usually, I’d decide on a width for the entire page (let’s say 960 pixels — it’s a popular size) and construct various widths based on that, perhaps indeed using a grid system from a framework. I’d like the topmost boxes to occupy one third of the width of the container, the second set of boxes one quarter, and the footer boxes one sixth, so I’ll divide accordingly using my handy calculator. I have a particular favorite green, which I’d like to use as a heading color for some boxes, a border color for the secondary headings, and as a background for the footer. There’s an item that looks kind of like the footer, but with a different font. Oh, and I’d like to add some basic font specifications to each of the sections — the text should become smaller the further you go down. All groovy:

#container {
  width: 960px;
}
.box {
  float: left;
}
#main .box {
  width: 320px;
}
#main .box h3 {
  background: #450;
}
#secondary {
  font-size: 90%;
}
#secondary .box {
  width: 240px;
  border-bottom: 1px solid #450;
}
#footer {
  font-size: 80%;
}
#footer, #super {
  background: #450;
  color: #fff;
}
#footer .box {
  width: 160px;
}
#super {
  font-family: cursive;
}

All groovy, that is, until I decide I’d like to change the width of the container. Now I have to go back and edit the widths of container and each of the descendent boxes on main, secondary, and footer. Then, I decide I’d like to use purple instead of green, so I then have to change the color of the main boxes’ headings, the secondary boxes’ borders, and the footer boxes’ backgrounds. Annoying!

Let’s imagine that I used Less for this task instead. First, of course, I’ll need to install Less, which is a quick job on the command line:

sudo gem install less

Now I’ll open a new text file and start writing Less. I’ll specify a
base width in a variable, @base:

@base: 960px;

And my favorite color:

@pretty: #450;

I’ll then use the @base variable to specify the widths of the main, secondary, and footer boxes as a fraction of that overall width. To define each of the box children of each section, I’ll use nested selectors to define how I want the box children of each section to appear. The @pretty variable is used wherever I need to specify that color. Here is the rest of my Less file:

#container {
  width: @base;
}
.box {
  float: left;
}

#main {
  .box {
    width: @base / 3;
      h3 {
        color: @pretty;
      }
  }
}

#secondary {
  font-size: 90%;
  .box {
    width: @base / 4;
    border-bottom: 1px solid @pretty;
  }
}

#footer {
  font-size: 80%;
  background: @pretty;
  color: #fff;
  .box {
    width: @base / 6;
  }
}

Since super looks just like footer, but with a different font, I’ll use Less’s class inclusion technique (they call it a mixin) to tell it to include these declarations too:

#super {
  #footer;
  font-family: cursive;
}

I’ll cook up a CSS file using this simple statement on the command line:

lessc mystylesheet.less

Out pops a style sheet with much the same content as the one I made in the usual fashion above, with the exception of my footer and super declarations. Rather than being grouped, the common declarations are repeated:

#footer {
  font-size: 80%;
  background: #450;
  color: #fff;
}
#super {
  font-size: 80%;
  background: #450;
  color: #fff;
  font-family: cursive;
}

More on that small annoyance later.

Now, since Less created much the same style sheet, you might be wondering where I’m going with this. Well, here’s where we come to the part where it’s time to change my mind about the width and color, and this is where Less really comes into its own. This time, I only need to change two lines in my style sheet. First up, let’s adjust the value of the base variable, like this:

@base: 720px;

Now, let’s change the green to purple:

@pretty: #619;

Now, I can leave the rest of the declarations alone and generate a new CSS file. The boxes’ width recalculations and color replacements are done for me:

#container {
  width: 720px;
}
.box {
  float: left;
}
#main .box {
  width: 240px;
}
#main .box h3 {
  color: #619;
}
#secondary {
  font-size: 90%;
}
#secondary .box {
  border-bottom: 1px solid #619;
  width: 180px;
}
#footer {
  font-size: 80%;
  background: #619;
  color: #fff;
}
#footer .box {
  width: 120px;
}

#super {
  font-size: 80%;
  background: #619;
  color: #fff;
  font-family: cursive;
}

Of course, this is a very simple example. In the real world, a complex grid-based template could contain dozens of declarations based on a single figure; a color scheme could revolve around two or three basic shades. Using Less, we can treat these base definitions as true variables, and spend less time maintaining them.

Less’s inclusion method could be tidier if it was clever enough to group the common elements of the mixed-in declarations. On the other hand, I kind of like the way it comes out here — I like to organize my style sheet into sections according to purpose:

/* heading styles */
...
/* main content styles */
...
/* footer styles */
...

If there’s a style I like the look of in the heading area, and I want an item in my footer to resemble it, I’d prefer to avoid storing that footer item in my headings section. If you want to be clever and use grouped selectors, you’ll have to put both those styles somewhere. The convenience of the feature outweighs this small nuisance for me, and of course using mixins is absolutely optional.

I love it when clever folk come up with great ways to save time on CSS, and I can see I’ll be making good use of this nifty tool in future. You can check out Less at its web site.

Sponsors