Revisiting Sass for smarter CSS.
Sun, Apr 17, 2011One 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…