Revisiting Sass for smarter CSS.

Sun, Apr 17, 2011

One of the downsides of using CSS is its lack of DRY-ness. Consider this trivial example where changing my borders from thin grey to thick white requires changes in 3 different places:

#header  { border-bottom: 1px solid #EEE; }
#sidebar { border-left:   1px solid #EEE; }
#footer  { border-top:    1px solid #EEE; }

Or here, changing the class name from post to article requires multiple changes:

.post          { padding: 0.5em; }
.post h1       { margin: 0; }
.post h1 .name { color: red; }
.post ul       { margin-top: 0.5em; }
  // (etc etc etc)

While there are ways to minimize these issues, any non-trivial CSS will eventually have a lot of duplication, and over the last few years a number of tools have been built to improve these problems. Most notably Sass and Less

When I first looked into these tools a year or so ago, I had expected a solution that just added variables and functions to existing CSS syntax. So when I looked at SASS and saw the Haml-like syntax I was disappointed.

When I looked at the syntax for LESS it felt more natural and closer to what I expected, but I was looking for a server-side Ruby solution, not a client-side (or node.js) javascript solution.

So I put the idea into the backlog and carried on with standard CSS

However, I must have missed the 3.0 release of SASS last summer, because I just re-discovered it, and with it comes a new scss syntax that looks pretty much how I imagined a smart CSS tool would work, so today I took another look…

Installation

Install is as simple as a gem install. If you want the stable 3.0 release, it still comes as part of the Haml gem:

sudo gem install haml

If you want the upcoming standalone 3.1 release, you can try out the edge version:

sudo gem install sass --pre

Both versions still support the original sass/haml format, but have introduced a new scss syntax that is simply a superset of css and fits much more naturally into existing traditional css-based projects.

The Sass home page has a clean, easy to understand, overview of the product and examples using either syntax.

There are really 4 main features that stand out for me…

Variables and Expressions

Colors and sizes can now be DRY-ed up and made much more manageable with the use of $ variables. In addition, sass allows some basic math operations inside property values, and some fancy color functions:

$border: 1px solid #EEE;
$space:  8px;
$blue:   #1080F0;

#header  { border-bottom: $border; padding: $space;     }
#sidebar { border-left:   $border; padding: $space / 2; }
#footer  { border-top:    $border; padding: $space * 2; }

a       { color: $blue;               }
a:hover { color: lighten($blue, 20%)  }

Mixins

With mixin’s you can re-use a set of styles without having to add multiple class names to elements, even better you can define a mixin that takes arguments:

@mixin round-corners   { border-radius: 4px }
@mixin panel($padding) { border: 1px solid #EEE; padding: $padding; }

#header  { @include panel(4px); @include round-corners; }
#footer  { @include panel(8px);                         }

Nesting

You can DRY up repeated selectors, and better match your intentions with nested CSS. Instead of:

#header              { background-color: #EEE; font-size: 1.25em; }
#header .title       { float: left; padding: 1em; margin: 1em;  }
#header .title .date { color: #999; }

You can now do this:

#header {

  background-color: #EEE;
  font-size:        1.25em;

  .title  {

    float:   left;
    padding: 1em;
    margin:  1em;

    .date { color: #999; }
  }
}

This one I’m actually not sure about. I actually kind of like the former format because its compact and I can see it all in one go, whilst the latter format is a bit more spread out and makes me think about which styles apply to which element.

Also, the more I rely on the latter format, the more of a switch I will have to make when building CSS for projects that don’t benefit from Sass.

I’ll have to try this out for a little while longer to see if I can decide if the benefits of DRY’ing up the selectors outweigh the (subjective) costs in readability.

Functions

And finally, you can define your own functions that can be called inside property values by extending the Sass::Script::Functions module:

module Sass::Script::Functions

  def seasonal_color
    color = case
            when Date.christmas? then 'red'
            when Date.stpatricks? then 'green'
            when Date.easter?     then 'yellow'
            else
              'white'
            end
    Sass::Script::String.new(color)
  end
 
end

A more useful custom method might be #image_path that can be used to generate the correct path to your background images.

Conclusion

The css for this website is fairly simple (not counting the included coderay syntax highlighting styles) but still benefits from the use of variables, mixins and a custom image_path function. Sass fits this need perfectly.

I might also try to introduce it at work (LiquidPlanner) where we have a much larger CSS codebase that could really benefit from some DRY-ness.

If you looked into Sass pre-version 3 and decided against it for the same reasons I did (largely an aversion to the Haml syntax), then you owe it to yourself to take another look. The introduction of the scss syntax, and the impending separation from HAML in upcoming v3.1 turns sass into a very nice standalone ruby smart stylesheet generator.

Go check it out…