CSS Pre-processors - LESS, SASS, Stylus

The problem with CSS pre-processors

CSS Pre-processors - LESS, SASS, Stylus

CSS Pre-processors – LESS, SASS, Stylus

I’ve been considering to use a CSS pre-processor like SASSLESSStylus, etc, for a very long time. Every time someone asked me if I was using any of these tools/languages I would say that I’m kinda used to my current workflow and I don’t really see a reason for changing it since the problems those languages solves are not really the problems I’m having with CSS. Then yesterday I read two blog posts which made me reconsider my point of view so I decided to spend some time today studying the alternatives (once again) and porting some code to check the output and if the languages would really help to keep my code more organized/maintainable and/or if it would make the development process easier (also if they evolved on the past few years).

It takes a couple hours for an experienced developer to learn most of the features present on these languages (after you learn the first couple languages the next ones are way easier) but if you have no programming skills besides CSS/HTML and/or don’t know basic programming logic (loops, functions, scope) it will probably take a while, the command line is another barrier to CSS/HTML devs… But that isn’t the focus of this post, I’m going to talk specifically about overused/misused features. I will try to explain the most common problems I see every time someone shows a code sample or I see a project written using any of these languages/pre-processors.

Mixins

What are mixins?

Mixin is a common name used to describe that an object should copy all the properties from another object. To sum up a mixin is nothing more than an advanced copy and paste. “All” the famous pre-processors have some kind of mixin.

Dumb code duplication is dumb

Following the SCSS syntax (sass), a mixin can be described and used as:

@mixin error {
    color: #f00;
    border: 2px solid #fc0;
}

.error-default {
    @include error;
}

.error-special {
    @include error;
    background-color: #fcc;
}

Which will compile to:

.error-default {
    color: #f00;
    border: 2px solid #fc0;
}

.error-special {
    color: #f00;
    border: 2px solid #fc0;
    background-color: #fcc;
}

Note that the properties are duplicated, which is very bad, file size will increase a lot and overall performance will also be degraded if not used with care. – Imagine that on a large project with thousands of lines of code, the amount of duplicated code will beunacceptable (by my standards).

This problem isn’t specific to SASS, it is also present on LESS and Stylus and any other language/pre-processor which supports the same feature, by having a new layer of abstraction the developer won’t realize he is creating code that has lots of duplication…ALWAYS gzip CSS and JS files!! gzip is really good at compressing duplicate data, so this problem might be irrelevant/nonexistent in production code, just beware that the generated CSS will get harder to maintain in case you or future devs for some reason decide to stop using a pre-processor and simply update the generated CSS (maybe they don’t have access to the source files or have no experience with a pre-processor).

Extend

LESS and Stylus doesn’t have support for anything similar to an extend, that’s why I picked SCSS (Sass) to write the code samples. A extend is like a “smarter mixin”, instead of copying and pasting the properties it will set the properties to multiple selectors at once.

.error {
    color: #f00;
    border: 2px solid #fc0;
}

.error-default {
    @extend error;
}

.error-special {
    @extend error;
    background-color: #fcc;
}

Which will compile to:

.error, .error-default, .error-special {
    color: #f00;
    border: 2px solid #fc0;
}

.error-special {
    background-color: #fcc;
}

Way closer to what a normal person would do manually… “Only” use mixins if you need to pass custom parameters. If you see yourself using the same mixin multiple times passing the same values than you should create a base “type” that is inherited by other selectors. – Compass (nice SASS framework) have a lot of mixins which I think should be base classesinstead.

Extend isn’t enough

Note that extend avoids code duplication but it also causes other problems, the amount of selectors can become an issue, if you @extend the same base class multiple times you may end up with a rule that have thousands of selectors, which won’t be good for performance either and can even make the browser to crash.

Another issue is that every class you create to be used only by @extend is going to be included on the compiled file (even if not used) which can be an issue in some cases (name collisions, file size) and makes this process not viable for creating a framework likecompass.

I really wish that SASS improves the way that @extend works (and that the other pre-processors also implements a similar feature) so we could create many base classes for code reuse but don’t necessarily export them. Something like:

@abstract error {
    color: #f00;
    border: 2px solid #fc0;
}

.error-default {
    @extend error;
}

.error-special {
    @extend error;
    background-color: #fcc;
}

Which would compile to:

.error-default, .error-special {
    color: #f00;
    border: 2px solid #fc0;
}

.error-special {
    background-color: #fcc;
}

PS: I know this kind of feature was already proposed before.

Another problem is if you mix nested selectors with @extends it might also causeundesired side-effects.

Extend and mixins can be bad for maintenance

Contrary to the common knowledge, extending other classes and creating mixins can degrade maintenance. Since the place where you are using the properties is far awayfrom where the properties are being defined there is a bigger chance that you will change properties without noticing you are affecting multiple objects at once, or not realizing which elements are being affected by the changes. This is called “tight coupling”:

Tightly coupled systems tend to exhibit the following developmental characteristics, which are often seen as disadvantages:

  • A change in one module usually forces a ripple effect of changes in other modules.
  • Assembly of modules might require more effort and/or time due to the increased inter-module dependency.
  • A particular module might be harder to reuse and/or test because dependent modules must be included.

(source: Wikipedia)

I prefer to group all my selectors by proximity, that way I make sure that when someone update a selector/property they know exactly what is going to be affected by these changes, even if that imply some code duplication.

Avoid editing base classes as much as possible, follow the “open/closed principle” as much as you can. (Augment base classes, do not edit them).

Nesting

Another feature that a lot of people consider useful is selector nesting, so instead of repeating the selectors many times you simply nest the rules that should be applied to child elements.

#content {

    table.hl {
        margin: 2em 0;

        td.ln {
            text-align: right;
        }

    }

}

Compiles to:

#content table.hl {
    margin: 2em 0;
}

#content table.hl td.ln {
    text-align: right;
}

By abstracting the selectors it becomes very easy to be over specific and specificity is hard to handle and a bad thing for maintainability. I’ve been following the OOCSSapproach and I don’t need child selectors that much so I don’t think that typing the same selector multiple times is a real problem (specially with good code completion), I know a lot of people don’t agree with that approach but for the kind of stuff I’m doing it’s been working pretty well.

Call me a weirdo but I also find nested code harder to read – since I’ve been coding non-nested CSS for more than 7 years.

Sum up

These tools have some cool features like the helper functions for color manipulation, variables, math helpers, logical operators, etc, but I honestly don’t think it would improve my workflow that much.

My feeling for these pre-processors is the same feeling I have for CoffeeScript, nice syntax and features but too much overhead for no “real” gain. Syntax isn’t the real problem in JavaScript for me the same way that it isn’t the real problem in CSS (and most of the languages). You still need to understand how the box-model works, specificity, cascading, selectors, floats, browser quirks, etc… you are just adding another layer of abstraction between you and the interpreted stylesheet, adding yet another barrier for future developers and increasing the chance of over-engineering. Markup may become simpler (with less classes/ids) but it comes with many drawbacks.

For me the greatest problem are developers that code CSS without the knowledge required to build a maintainable and scalable structure. A stylesheet full of mixins, if/else, loops, variables, functions, etc, will be as hard to maintain as a bloated hand-crafted stylesheet, if not harder. Developers have an inherited desire to be “clever” and that is usually a red flag.

“Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?” – Brian Kernighan

Mixins are popular nowadays because of browser vendor prefixes, the real problem isn’t that CSS doesn’t support mixins or variables natively but that we have to write an absurd amount of vendor prefixes for no real reason since most of the implementations are similar and most of the features are only “cosmetic”. The real issue isn’t the language syntax, but the way that browsers are adding new features and people using them before they are implemented broadly (without prefixes). – This could be handled by a pre-processor that only adds the vendor prefixes (without the need of mixins or a special language) like cssprefixerTry to find what is the real problem you are trying to solve and think about different solutions.

“It’s time to abolish all vendor prefixes. They’ve become solutions for which there is no problem, and they are actively harming web standards.” – Peter-Paul Koch

I’ve been following the OOCSS approach on most of my latest projects, and probably will keep doing it until I find a better approach. For the kind of stuff I’m coding it is more important to be able to code things fast and make updates during the development phase than to maintain/evolve the project over many months/years. I find it very unlikely to make drastic design changes without updating the markup, on the last 100 projects I coded it probably only happened 2 or 3 times. – css zen garden is a cool concept but not really that practical – Features like desaturate(@red, 10%) are cool but usually designers already provides me a color palette to be used on the whole site and I don’t duplicate the same value that much, if I do duplicate it everywhere than I can simply do a “find and replace” inside all the CSS files and call it a day, by using a function that generates a color (which you have no idea which value it will be) you can’t simply do a find and replace since you don’t know what is the value you are looking for on the source code – I prefer to simply use a color picker…

I know my experience is very different from most people so that’s why my approach is also different, your mileage may vary… If I ever need to use any of these tools it won’t be an issue (I have no strong barrier against them), I just don’t think they will save me that much time right now that would outweigh the drawbacks. Pick the tools based on the project and your workflow, it isn’t because I listed a couple issues that you should discard using a pre-processor, for many cases it would be an awesome way of generating stylesheets, just think about the drawbacks and be responsible.

“With great power comes great responsibility.” – Uncle Ben to Peter Parker

PS: I love CSS, for me it’s one of the most rewarding tasks on a website development, it’s like solving a hard puzzle…

Source – millermedeiros.com

Advertisements