I love Sass. I use it everyday in my front-end workflow and know that my productivity would suffer if it were taken away. It’s an awesome tool and one that has truly pushed CSS standards forward.
Sass gives us the power to do all sorts of amazing things to make writing CSS more succinct and maintainable, with the barrier to entry being fairly low. However, reading a recent A List Apart article, confirmed a thought that had been niggling away at me for a little while now.
Are we abusing the power of Sass to perform pre-processing micro optimisations that shouldn't be done in the first place?
The above ALA article was written by Sam Richard and he nails some really great points on some simple ways to DRY out your Sass. Placeholder selectors can be very useful. I don’t personally use @extend
that much, mainly due to the unexpected output it can sometimes generate, but I definitely don’t have a problem with anyone else using it and can see it’s value in keeping your Sass well structured.
Deeper into the article, he goes on to show how to DRY out a mixin to the point where we have the following Sass:
$Placeholder-Selectors: ();
@mixin button($color, $extend: true) {
@include button-static($extend);
background-color: $color;
border-color: mix(black, $color, 25%);
&:hover {
background-color: mix(black, $color, 15%);
border-color: mix(black, $color, 40%);
}
}
@mixin button-static($extend: true) {
$button-selector: map-get($Placeholder-Selectors, 'button');
@if $extend == true {
@if $button-selector == null {
$button-selector: unique-id();
$Placeholder-Selectors: map-merge($Placeholder-Selectors, ('button': $button-selector)) !global;
@at-root %#{$button-selector} {
@include button-static(false);
}
}
@extend %#{$button-selector};
}
@else {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
}
Which can then be used in the following way:
.button-badass {
@include button(#b4d455);
}
.button-coffee {
@include button(#c0ffee);
}
.button-decaff {
@include button(#decaff);
}
.button-badass {
background-color: #b4d455;
border-color: #879f3f;
}
.button-badass,
.button-coffee,
.button-decaff {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
}
.button-badass:hover,
.button-coffee:hover,
.button-decaff:hover {
cursor: pointer;
}
.button-badass:hover {
background-color: #99b448;
border-color: #6c7f33;
}
.button-coffee {
background-color: #c0ffee;
border-color: #90bfb2;
}
.button-coffee:hover {
background-color: #a3d8ca;
border-color: #73998e;
}
.button-decaff {
background-color: #decaff;
border-color: #a697bf;
}
.button-decaff:hover {
background-color: #bcabd8;
border-color: #857999;
}
First off – creating a mixin that can do this is hugely skilled. It does exactly what it was written to do, plus it's uber DRY. Mission accomplished right?
But here-in lies my problem; how maintainable is that mixin should another developer take over the project?
I don’t consider myself a Sass newbie by any means – I've been using it for over 2 years and feel that I can do everything I need to in order to build great websites – yet I took one look at that mixin and it scared the crap out of me. In fact, it still does and I've looked at it a dozen times now. If I took over maintaining a project and all the Sass looked as complex as that, I’d feel a little out of my depth maintaining the project.
So is this my problem for not knowing some of the intricacies of Sass? Should we all be chasing this level of DRY-ness in our code?
In my opinion, I don’t think it is and I don’t think we necessarily should be.
One of CSS's biggest strengths is it’s simplicity. Sass has proved beyond any doubt that there are areas in which CSS can be improved upon, but abstracting it to such a level that it becomes almost unintelligible to anyone but expert users of a preprocessor isn’t one of them.
If we're making our Sass this complex simply to save a couple of lines surplus code, this seems counter productive. You could liken it to golfing your JavaScript on a production website in a style seen in JS1k competitions; it takes a very skilled developer to write JavaScript that succinct, but when writing code for a production website the same developers would code in a more maintainable way, else it would be impossible to maintain down the line.
If more maintainable code comes in slightly larger than the DRY-er alternative, making sure you optimise your CSS when the code hits production servers will make this difference minimal. Ensure you compress and Gzip your CSS – Gzip is actually really good at squishing repetitive text.
Part of a developers job is to write maintainable code so that should we get hit by a bus – or any form of transport – on the way to work, another developer could pick up our project with relative ease. This doesn't mean we all have to code to a basic level, but it should mean that we try not to overcomplicate things for minimal gains.
Although I've highlighted Sass in this article, this goes for any code that we write; DRY isn't the be all and end all of coding and, as Joel Abrahamsson mentions in his article The DRY Obsession, blindly applying DRY can quickly do more harm than good.
So before we all start attempting to create the DRY-est mixins the world has ever seen, take a step back and think of the DRY-est form of CSS we can create; CSS itself.
The problem tackled by the mixin above can also be solved by defining an extra class and adding that classname to each button element in the markup, extending each buttons specific properties. It is slightly less succinct, but is much more maintainable and any developer would be able to understand and build upon it.
If you find you are duplicating properties to the point of needing a mixin, then by all means go ahead and create one. But don’t micro-optimise to the n-th degree if it means only you will understand how to modify that code in the future.
Article posted on the 29th May 2014