Doing More with LESS

Microsoft’s Visual Studio Web Essentials extension is probably the quickest and easiest way to get LESS stylesheets enabled in your ASP.NET project. They have a page that doesn’t say much about it. Once it’s in, you can “Add new item > StyleSheetLESS” and this will give you three items: the LESS stylesheet that you edit, the CSS stylesheet that you use if you’re bundling and minifying as part of the build after debugging locally, and the minified CSS stylesheet that you may use if you’re not minifying and bundling as part of your build process.

Warnings: Bugs in your LESS stylesheet will cause the CSS file to not generate. And your CSS file may not generate when you want it to — be sure to check “Tools > Options > Web Essentials > LESS” and ensure that “Generate CSS file on save” and “Show preview window” are both set to true to minimize the likelihood that the tool will betray you. Finally, if you’ve bugged your LESS but can’t figure out how because it doesn’t proactively pop up the error list, Error List is about halfway down in the “View” menu (or Ctrl+\, E using default keybindings).

But if you’re like me, you’ve been using CSS all millennium long (so far) and are probably wondering why you should change to this new fad that is on your virtual lawn. And the answer is simple: You Hate CSS. You hate CSS because CSS was not written for programmers. Programmers believe in making things DRY (“Don’t Repeat Yourself”) and CSS has a disgusting tendency towards being SOGgy (“Slimy Organic Growth”) as overrides, conditionals, and one-offs layer over the not-necessarily-used cruft inherited from external agencies, contractors, corporate branding, and that intern from two years ago.

LESS Power #0: Nesting instead of repeating selectors. This one should’ve been obvious 15 years ago:

.big-class {
  font-size: 1.2em;
  margin: 4px;
  .sub-box {
    padding: 4px;
    &:hover {
      text-decoration: underline;
    }
  }
}

I’m going to trust that since you know this compiles down to CSS I don’t have to spell out that it’ll build rules for .big-class and .big-class .sub-box and .big-class .sub-box:hover, right?

LESS Power #1: Consistent values via variables. How many times does your current CSS set border radius? I ask, because every one of them could be different. The first basic power of LESS is to set a variable (preferably at the top of your LESS), like this:
@button-border-radius: 3px;
And then you can use it all over the place like this:
.button-green { color: green; border-radius: @button-border-radius; }
.button-blue { color: blue; border-radius: @button-border-radius; }

Or we could take it step further and have the radius be a mix-in:
.round-corners { border-radius: @button-border-radius; }
.button-green { color: green; .round-corners; }
.button-blue { color: blue; .round-corners; }

The mix-in technique is particularly useful when resetting fonts, margins, and paddings early in the de-crufting process.

Warning: Just because you’re not repeating yourself doesn’t mean that CSS has magically become not-dumb. The compiled CSS will copy the content of variables and mix-ins to wherever they’re used resulting in no savings for your end user. This is preferable to you copying them yourself, but not permission to get sloppy with them.

LESS Power #2: Color palette control. How many colors are in your color palette? Probably very few, but then expanded out to be a crazy number when you’ve got variants and shades and hues and such. LESS can help you bring your colors under control with functions. Let’s start by taking one of our favorite colors that is important and defining it:
@link-blue: #0071C5;
Now this is our most important blue, so when we do other blues, we want to keep them in line with this blue. For example, if we want a background blue that’s like this, but more grey so that it’s got a “not clickable” vibe to it, we can use the LESS “desaturate” function like this:
@flat-blue: desaturate(@link-blue, 30%);
LESS documentation naturally features the full list of LESS functions, but I’ll go over a few more here.
Now that we can manipulate our colors a bit, it’s time to mix them in to interesting situations. For example, let’s make those blue and green buttons stand out a bit with consistently applied gradients. First we’ll write a parameterized mix-in like this:

.background-gradient (@bgcolor) {
  background: none;
  background-color: @bgcolor;
  background-image: -webkit-linear-gradient(bottom, darken(@bgcolor, 10%) 1%, 
      @bgcolor 20%, lighten(@bgcolor, 10%) 92%);
  background-image: linear-gradient(to top, darken(@bgcolor, 10%) 1%, 
      @bgcolor 20%, lighten(@bgcolor, 10%) 92%);
}

and then we’ll drop it in to our buttons
@selected-green: #1C1;
.button-green { .background-gradient(@selected-green); .round-corners; }
.button-blue { .background-gradient(@link-blue); .round-corners; }

And now when we have to change our gradient declaration to keep up with browser compatibility or simply on the fashionable whims of corporate branding, we’ve got one place to change it for our entire site, regardless of how many colors get used.

For our special bonus, I’d like to give a shout out to the inset box shadow which I use to highlight things (like buttons or table cells when a hover event is detected, though in the future it’ll be tied to eye-tracking, I’m sure):

.highlight-element(@highlight-color) {
  background: @highlight-color;
  box-shadow: inset 0 0 .45em darken(@highlight-color, 40%);
}

Note that this expects a light highlight color and darkens the edges; you can reverse this by changing the darken() on the box-shadow to lighten() on the background and giving it a dark color to start, of course: the color values are pre-compiled by the LESS compiler saving you from the worry of browser compatibility on that point.

LESS Power #4: Retro sizing calculations that work. If you’re living under the imposing thumb of corporate standards that aren’t yet fluid and responsive — this year they’re “old school,” next year they’ll step it up to “retro” so as to not fall behind the times — then you’re thinking about box sizes, and those box sizes are probably based on the sizes of background graphics that you’re not even using because you’ve got gradients and box-shadows and all manner of great built-in capabilities. Well, let’s add another great capability: calculated sizes. Start by defining some variables

@core-width: 960px;
@core-pad: 10px;
@element-pad: 8px;

And then we lay down our wide centered block:

.main-center {
  float: none;
  width: @core-width;
  margin: 0 auto @core-pad; /* Center our main block */
  background-color: #fff;
}

Note that I’m not re-defining white because it’s white. If we had any doubts about leaving white as white, I’d have re-defined white. But declaring that @white: white; is silly so I didn’t do it.

Now that we’ve got our block in which all content gets uncerimoniously dumped, let’s show what the cool stuff is:

.w-737 { /* left nav + wide right block */
  width: (@core-width * .78 - @core-pad);
}
.w-517 { /* left nav + wider middle + right nav */
  width: (@core-width * .56);
}
.con-rcl, .con-lcl { /* left & right columns */
  width: ((@core-width * .22) - (@core-pad + @element-pad ));
  z-index: 2;
  display: inline;
  position: relative;
}
.con-rcl {
  float: right;
}
.oneThird /* 3 columns */
{
  .reset-spacing;
  width: ((@core-width * .333) - 
      (@element-pad + (@box-border-width * 2) + (@core-pad * .667))); 
  /* 2 core pads div 3 columns; borders not inside these boxen */
  float: left;
  margin-right: @element-pad;
  .box-border;
}

So what you can see here is that we can take a quantity of pixels, apply a percentage to it (like “width: 33%” would imply) and then modify it to account for margins, paddings, borders, outlines, and whatever else might be required by our box model. If you need a refresher on box models, this looks like a decent one.

And that’s what LESS does for us. We started with not repeating our selectors across rules. Then we mixed in not repeating our consistent values or style settings across rules. Then we built an actual color palette from functions instead of just tweaking hex values until they looked okay. And finally we made woefully old-school element widths less woeful using the LESS compiler’s calculations.

These examples came out of a project that’s been around since the days of supporting IE6 and had many hands working over it. Converting over to LESS and eliminating over half our styles while giving the site a UI scrub-down (and no longer pandering to IE8) took me less than a week and while it’s not the prettiest of pigs, it is now wearing a more reasonable amount of lipstick which is confined to its lips.

In terms of business impact, this gives us

  • stylesheets that are easier (and thus cheaper) for developers to maintain,
  • stylesheets that are shorter for bandwidth cost savings,
  • and, when delivered, client browser resource savings which improves user experience.

Put it together and I think you’ve got a compelling case for doing LESS at work.