Illustration by

A Vision for Our Sass

At a recent CSS meetup, I asked, “Who uses Sass in their daily workflow?” The response was overwhelmingly positive; no longer reserved for pet projects and experiments, Sass is fast becoming the standard way for writing CSS.

Article Continues Below

This is great news! Sass gives us a lot more power over complex, ever-growing stylesheets, including new features like variables, control directives, and mixins that the original CSS spec (intentionally) lacked. Sass is a stylesheet language that’s robust yet flexible enough to keep pace with us.

Yet alongside the wide-scale adoption of Sass (which I applaud), I’ve observed a steady decline in the quality of outputted CSS (which I bemoan). It makes sense: Sass introduces a layer of abstraction between the author and the stylesheets. But we need a way to translate the web standards—that we fought so hard for—into this new environment. The problem is, the Sass specification is expanding so much that any set of standards would require constant revision. Instead, what we need is a charter—one that sits outside Sass, yet informs the way we code.

To see a way forward, let’s first examine some trouble spots.

The symptoms#section1

One well-documented abuse of Sass’s feature-set is the tendency to heavily nest our CSS selectors. Now don’t get me wrong, nesting is beneficial; it groups code together to make style management easier. However, deep nesting can be problematic.

For one, it creates long selector strings, which are a performance hit:

body #main .content .left-col .box .heading { font-size: 2em; }

It can muck with specificity, forcing you to create subsequent selectors with greater specificity to override styles further up in the cascade—or, God forbid, resort to using !important:

body #main .content .left-col .box .heading  [0,1,4,1]
.box .heading  [0,0,2,0]
Comparative specificity between two selectors.

Last, nesting can reduce the portability and maintainability of styles, since selectors are tied to the HTML structure. If we wanted to repeat the style heading for a box that wasn’t in the leftcol, we would need to write a separate rule to accomplish that.

Complicated nesting is probably the biggest culprit in churning out CSS soup. Others include code duplication and tight coupling—and again, these are the results of poorly formed Sass. So, how can we learn to use Sass more judiciously?

Working toward a cure#section2

One option is to create rules that act as limits and reign in some of that power. For example, Mario Ricalde uses an Inception-inspired guideline for nesting: “Don’t go more than four levels deep.”

Rules like this are especially helpful for newcomers, because they provide clear boundaries to work within. But few universal rules exist; the Sass spec is sprawling and growing (as I write this, Sass is at version 3.4.5). With each new release, more features are introduced, and with them more rope with which to hang ourselves. A rule set alone would be ineffective.

We need a proactive, higher-level stance toward developing best practices rather than an emphasis on amassing individual rules. This could take the form of a:

  • Code standard, or guidelines for a specific programming language that recommend programming style, practices, and methods.
  • Framework, or a system of files and folders of standardized code, which can be used as the foundation of a website.
  • Style guide, or a living document of code, which details all the various elements and coded modules of your site or application.

Each approach has distinct advantages:

  • Code standards provide a great way of unifying a team and improving maintainability across a large codebase (see Chris Coyier’s Sass guidelines).
  • Frameworks are both practical and flexible, offering the lowest barrier to entry and removing the burden of decision. As every seasoned front-end developer knows, even deciding on a CSS class name can become debilitating.
  • Style guides make the relationship between the code and the output explicit by illustrating each of the components within the system.

Each also has its difficulties:

  • Code standards are unwieldy. They must be kept up-to-date and can become a barrier to entry for new or inexperienced users.
  • Frameworks tend to become bloated. Their flexibility comes at a cost.
  • Style guides suffer from being context-specific; they are unique to the brand they represent.

Unfortunately, while these methods address the technical side of Sass, they don’t get to our real problem. Our difficulties with Sass don’t stem from the specification itself but from the way we choose to use it. Sass is, after all, a CSS preprocessor; our Sass problem, therefore, is one of process.

So, what are we left with?

Re-examining the patient#section3

Every job has its artifacts, but problems arise if we elevate these by-products above the final work. We must remember that Sass helps us construct our CSS, but it isn’t the end game. In fact, if the introduction of CSS variables is anything to go by, the CSS and Sass specs are beginning to converge, which means one day we may do away with Sass entirely.

What we need, then, is a solution directed not at the code itself but at us as practitioners—something that provides technical guidelines as we write our Sass, but simultaneously lifts our gaze toward the future. We need a public declaration of intentions and objectives, or, in other words, a manifesto.

Sass manifesto#section4

When I first discovered Sass, I developed some personal guidelines. Over time, they formalized into a manifesto that I could then use to evaluate new features and techniques—and whether they’d make sense for my workflow. This became particularly important as Sass grew and became more widely used within my team.

My Sass manifesto is composed of six tenets, or articles, outlined below:

  1. Output over input
  2. Proximity over abstraction
  3. Understanding over brevity
  4. Consolidation over repetition
  5. Function over presentation
  6. Consistency over novelty

It’s worth noting that while the particular application of each article may evolve as the specification advances, the articles themselves should remain unchanged. Let’s cover each in a little more depth.

1. Output over input#section5

The quality and integrity of the generated CSS is of greater importance than the precompiled code.

This is the tenet from which all the others hang. Remember that Sass is one step in the process toward our goal, delivering CSS files to the browser. This doesn’t mean the CSS has to be beautifully formatted or readable (this will never be the case if you’re following best practices and minimizing CSS), but you must keep performance at the forefront of your mind.

When you adopt new features in the Sass spec, you should ask yourself, “What is the CSS output?” If in doubt, take a look under the hood—open the processed CSS. Developing a deeper understanding of the relationship between Sass and CSS will help you identify potential performance issues and structure your Sass accordingly.

For example, using @extend targets every instance of the selector. The following Sass

.box {
	background: #eee;
	border: 1px solid #ccc;

	.heading {
	  font-size: 2em;
	}
}

.box2 {
	@extend .box;
	padding: 10px;
}

compiles to

.box, .box2 {
  background: #eee;
  border: 1px solid #ccc;
}
.box .heading, .box2 .heading {
  font-size: 2em;
}

.box2 {
  padding: 10px;
}

As you can see, not only has .box2 inherited from .box, but .box2 has also inherited from the instances where .box is used in an ancestor selector. It’s a small example, but it shows how you can arrive at some unexpected results if you don’t understand the output of your Sass.

2. Proximity over abstraction#section6

Projects should be portable without over-reliance on external dependencies.

Anytime you use Sass, you’re introducing a dependency—the simplest installation of Sass depends on Ruby and the Sass gem to compile. But keep in mind that the more dependencies you introduce, the more you risk compromising one of Sass’s greatest benefits: the way it enables a large team to work on the same project without stepping on one another’s toes.

For instance, along with the Sass gem you can install a host of extra packages to accomplish almost any task you can imagine. The most common library is Compass (maintained by Chris Epstein, one of Sass’s original contributors), but you can also install gems for grid systems, and frameworks such as Bootstrap, right down to gems that help with much smaller tasks like creating a color palette and adding shadows.

These gems create a set of pre-built mixins that you can draw upon in your Sass files. Unlike the mixins you write inside your project files, a gem is written to your computer’s installation directory. Gems are used out-of-the-box, like Sass’s core functions, and the only reference to them is via an @include method.

Here’s where gems get tricky. Let’s return to the scenario where a team is contributing to the same project: one team member, whom we’ll call John, decides to install a gem to facilitate managing grids. He installs the gem, includes it in the project, and uses it in his files; meanwhile another team member—say, Mary—pulls down the latest version of the repository to change the fonts on the website. She downloads the files, runs the compiler, but suddenly gets an error. Since Mary last worked on the project, John has introduced an external dependency; before Mary can do her work, she must debug the error and download the correct gem.

You see how this problem can be multiplied across a larger team. Add in the complexity of versioning and inter-gem-dependency, and things can get very hairy. Best practices exist to maintain consistent environments for Ruby projects by tracking and installing the exact necessary gems and versions, but the simplest approach is to avoid using additional gems altogether.

Disclaimer: I currently use the Compass library as I find its benefits outweigh the disadvantages. However, as the core Sass specification advances, I’m considering when to say goodbye to Compass.

3. Understanding over brevity#section7

Write Sass code that is clearly structured. Always consider the developer who comes after you.

Sass is capable of outputting super-compressed CSS, so you don’t need to be heavy-handed in optimizing your precompiled code. Further, unlike regular CSS comments, inline comments in Sass aren’t outputted to the final CSS.

This is particularly helpful when documenting mixins, where the output isn’t always transparent:

// Force overly long spans of text to truncate, e.g.:
// @include truncate(100%);
// Where $truncation-boundary is a united measurement.

@mixin truncate($truncation-boundary){
    max-width:$truncation-boundary;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
}

However, do consider which parts of the your Sass will make it to the final CSS file.

4. Consolidation over repetition#section8

Don’t Repeat Yourself. Recognize and codify repeating patterns.

Before you start any project, it’s sensible to sit down and try to identify all the different modules in a design. This is the first step in writing object-oriented CSS. Inevitably some patterns won’t become apparent until you’ve written the same (or similar) line of CSS three or four times.

As soon as you recognize these patterns, codify them in your Sass.

Add variables for recurring values:

$base-font-size: 16px;
$gutter: 1.5em;

Use placeholders for repeating visual styles:

%dotted-border { border: 1px dotted #eee; }

Write mixins where the pattern takes variables:

//transparency for image features
@mixin transparent($color, $alpha) {
  $rgba: rgba($color, $alpha);
  $ie-hex-str: ie-hex-str($rgba);
  background-color: transparent;
  background-color: $rgba;
  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex-str},endColorstr=#{$ie-hex-str});
  zoom: 1;
}

If you adopt this approach, you’ll notice that both your Sass files and resulting CSS will become smaller and more manageable.

5. Function over presentation#section9

Choose naming conventions that focus on your HTML’s function and not its visual presentation.

Sass variables make it incredibly easy to theme a website. However, too often I see code that looks like this:

$red-color: #cc3939; //red
$green-color: #2f6b49; //green

Connecting your variables to their appearance might make sense in the moment. But if the design changes, and the red is replaced with another color, you end up with a mismatch between the variable name and its value.

$red-color: #b32293; //magenta
$green-color: #2f6b49; //green

A better approach is to name these color variables based on their function on the site:

$primary-color: #b32293; //magenta
$secondary-color: #2f6b49; //green

Presentational classes with placeholder selectors#section10

What happens when we can’t map a visual style to a functional class name? Say we have a website with two call-out boxes, “Contact” and “References.” The designer has styled both with a blue border and background. We want to maximize the flexibility of these boxes but minimize any redundant code.

We could choose to chain the classes in our HTML, but this can become quite restrictive:

<div class="contact-box blue-box">
<div class="references-box blue-box">

Remember, we want to focus on function over presentation. Fortunately, using the Sass @extend method together with a placeholder class makes this a cinch:

%blue-box {
	background: #bac3d6;
	border: 1px solid #3f2adf;
}

.contact-box {
	@extend %blue-box;
	...
}
.references-box {
@extend %blue-box;
	...
}

This generates the following CSS, with no visible references to %blue-box anywhere, except in the styles that carry forward.

.contact-box,
.references-box {
	background: #bac3d6;
	border: 1px solid #3f2adf;
}

This approach cuts references in our HTML to presentational class names, but it still lets us use them in our Sass files in a descriptive way. Trying to devise functional names for common styles can have us reaching for terms like base-box, which is far less meaningful here.

6. Consistency over novelty#section11

Avoid introducing unnecessary changes to the processed CSS.

If you’re keen to introduce Sass into your workflow but don’t have any new projects, you might wonder how best to use Sass inside a legacy codebase. Sass fully supports CSS, so initially it’s as simple as changing the extension from .css to .scss.

Once you’ve made this move, it may be tempting to dive straight in and refactor all your files, separating them into partials, nesting your selectors, and introducing variables and mixins. But this can cause trouble down the line for anyone who is picking up your processed CSS. The refactoring may not have affected the display of anything on your website, but it has generated a completely different CSS file. And any changes can be extremely hard to isolate.

Instead, the best way to switch to a Sass workflow is to update files as you go. If you need to change the navigation, separate that portion into its own partial before working on it. This will preserve the cascade and make it much easier to pinpoint any changes later.

The prognosis#section12

I like to think of our current difficulties with Sass as growing pains. They’re symptoms of the adjustments we must make as we move to a new way of working. And an eventual cure does exist, as we mature in our understanding of Sass.

It’s my vision that this manifesto will help us get our bearings as we travel along this path: use it, change it, or write your own—but start by focusing on how you write your code, not just what you write.

About the Author

Felicity Evans

Felicity Evans is a front-end developer for Fairfax Media, and lives in Sydney, Australia. She loves food, color, and building things with pixels. She also tweets intermittently under the name @webfliccy.

29 Reader Comments

  1. Thanks Felicity. This is all great. I would only add one more tenant: Simplicity Over Complexity. Perhaps this is implicit in your tenants already. I have just seen some SASS code that boggles my mind why anyone would want write or manage it.

    At some point it stops, in my mind, becoming a superset of CSS and rivaling the complexity of lower-level languages. I don’t want that for anybody using SASS.

  2. Great credo. I know in the past I’ve been guilty of writing sass variables that name colours 🙂 Awesome tips.

    I was contemplating the gem issue you mention. Each project I work has a package.json file that includes all of the dev dependencies. It even goes so far as to include exact versions. This is all done automatically with node. That way if someone else picks up the project they simply type ‘npm install’, and it will include and install all the required dependencies.

  3. I love Sass, but I’d hesitate to call it a standard. This year in particular I’ve noticed a slight backlash against Sass due to its sluggish performance (made worse by a lack of parity with the speedier libsass) as well as its propensity for bloated CSS if you aren’t careful (as described in this article).

    If one truly fears losing control of their preprocessor’s output, it might be time to evaluate some alternative solutions. Stylus has some nifty features like “cachable” mixins that can decrease redundancy in oft-used mixins. rework lets you roll your own preprocessor by installing only the plugins you need (most of them based on real W3 draft specs), which has resulted in a bunch of really cool spinoff projects like SUIT CSS, styl, Myth and Resin.

    As awesome as Sass is, it would be a shame if we let the alternatives flounder simply out of habit. Monocultures are boring, right?

  4. “The simplest installation of Sass depends on Ruby and the Sass gem to compile.” I might argue that libsass is simpler. At least to someone like me who doesn’t use ruby.

    Also, if using build tools like Grunt or gulp, it’s easy to use postprocessors like autoprefixer to do much of what compass does. I’m admittedly a beginner, but I haven’t seen a compelling reason yet to use compass.

  5. Chris, Agreed. One of the greatest advantages of Sass is that its syntax is easy to pick up for those who know CSS and this can be lost when too much complexity is introduced.

    Pierre, Yes Hugo Giraudel’s guidelines came out between the time I’d finished writing this article and its publication. Otherwise they would have featured here. A great resource to be sure.

    Tyler, As some people have noted the tenets can be applied more broadly to CSS preprocessors in general. Whilst I think Sass will remain the front-runner I am not ruling out another technology gaining prominence; fortunately many of these languages share a lot of underlying principles.

    Ian, I hesitated over which word to use here. Perhaps “standard” would be better than “simplest”. As LibSass is now on par with Ruby Sass I think we’ll see more people using it.

    Ezekiel, Great spot. I’ve fed back to the editorial team who should update. Thanks.

  6. Thanks for the great article. It’s always good to have a vision for your Sass codebase. I’m surprised you didn’t mention scss-lint, which helps enforcing these rules in an automated fashion, have you tried using it on a project before, and if so, did you like it?

  7. Felicity, nice article. You’ve reaffirmed my gripes with Sass and current CSS pre-processors in general.

    I understand the logic in starting with the CSS language and then adding to the syntax, however what you end up with is just ANOTHER language to learn, another set of tools to maintain, another set of dependencies, and a whole bunch of things to consider (as is the case with any language), which your article attests to.

    “With each new release, more features are introduced”

    Sass now has loops, lists, maps, variables, functions, conditional statements, scope, etc, etc. Why not flip this on its head. Why not start with an established language and use it to author our CSS. A language that is already part of all front-end stacks, a language that any front-end developer is immediately familiar with, a language that has mature tooling, styles guides, documentation, resources. Why not use JavaScript? Syntax maybe?

    As a proof of concept:

    http://codepen.io/webstack/pen/JoNayy

    I’m not suggesting this would address all the issues you’ve mentioned, but for the issues it doesn’t address, at least they would be confined to a single language.

    While technically you could use this in place of CSS files, I’m suggesting this purely for authoring the CSS. Although, it could have some interesting applications if used at runtime!

  8. Even though I agree with most of the hints and advises, I must disagree concerning nesting
    – in most cases even deep nesting (10-20 levels) does NOT have a noticeable performance impact
    – the maintainability is usually not a big issue either.If you just add another wrapper-div to make the component work with your Javascript/CMS/whatever requires it, the CSS probably won’t break. If you remove something from your html structure, you usually want to change the corresponding CSS/SASS as well. It’s not like CSS-Properties only affect your selected element, they also effect their child elements quite a lot (e.g. inherited styles, using position:relative so that the child element may use position:absolute, …)
    – I’ve experienced, that nesting even improves the readability (and therefore the maintainability) of your styles.
    – If you have appropriate default styles, you usually don’t have to style every single element again. It’s not like your SASS-Nesting-structure is exactly the DOM-structure, it’s usually much less.

    I’ve read so many articles (including from Hugo Giraudel) and I’m still strongly convinced, that the advantages of nesting (even if you get up to 10 levels) definitely outweigh the disadvantages.

  9. Kaelig, I intentionally shied away from solutions directed “at the code” since the manifesto is intended for us “the coders”. That said; once you’ve decided on some code standards a linter is a great way to keep everyone on track. We’ve just begun using scss-lint in our workflow. Early signs are good 🙂

    Alessandro, glad to be of service.

    Sephen S, the benefits of using Sass would fill another article; suffice-to-say that while I have focussed on the pitfalls here I think the advantages far outweigh the costs. One of the biggest changes that helped increase the take up of Sass is when they moved to the scss syntax as it mimicked css, I think your js solution is novel but I’ll be sticking to my Sass for now!

    MattDiMu, I see that on a small project nesting might not be an issue but on large sites / networks where modules can be reused in multiple places / pages / sites heavy nesting is THE BIGGEST culprit in causing css problems. At least, that has been my experience.

  10. “Understanding over brevity”

    That point can’t be stressed enough.
    A solid understanding of CSS *outside* of pre-processing is essential.

    Aside from a deep understanding, this excellent article also points out the next most important thing, modularity.

    At this point, I set aside CSS while I think about exactly *what* components my website has – where are the similarities?

    What is *generic* and what is *specific* (bespoke). ?

    For large, complex websites or web applications, this is often the most difficult starting point, done before even coding a single line of css.

    For smaller websites, it’s often as simple as re-using existing well written sass and simply changing the variables.

  11. Matt, I agree whole-heartedly. We don’t build web *pages* anymore we build web *systems* composed of modules that are stitched together.

    Ivan, how very philosophical of you! If we have ourselves to blame, perhaps we can help ourselves too?

  12. Hi Felicity,
    great article and very good to understand.
    Using the placeholder class blue-box and later the design is changing to a red box, i have to replace all occurrences of blue box, right? Is there a better solution? I think the problem is only moved from the HTML to the scss-file.

  13. Fantastic article – really underlines how making life simple can be … complex.

    DRY and Modular – so easy to *talk* about, but so very difficult to implement.

    The way I try to teach / explain effective CSS is to ask the question “If I take this widget/feature *out* of it’s parent, will it still render correctly?”

    “Within this feature, we have common features – will *they* still render correctly *outside* of our feature, our widget?”

    It boils down to documenting all the commonalities of a website/webapp before writing a single line of code (or adopting a framework or parts thereof)

    That is no mean feat, but is paramount to effective, easily maintainable and efficient css output.

  14. Yes, Felicity. It must start with us.

    I don’t use pre-processors since I know the CSS code well enough but will need to start using it to deal with all the bad pre-processor CSS that is being sent to me from other sources.

    Writing good CSS is not dependent on SASS/LESS/etc.

    “Blame the player, not the instrument.”

  15. Great article Felicity!

    One question I had though was concerning “Output over Input”. In the code example, you showed what NOT to do with SASS, correct? What would be the correct way to code that example so we get the desired CSS output?

  16. It’s not SASS specific, but Harry Roberts (CSS Wizardry) also has a great set of guidelines for CSS, which are great for reference, even if you don’t agree with or adapt all of them. http://cssguidelin.es

    Mark Otto (Bootstrap) has another one with a bunch of hard to argue guidelines. Again, not SASS specific, but very helpful for avoiding some of the pitfalls that SASS can seduce us into. http://codeguide.co

  17. Hey dear,doyou know about free itunes codes and itunes gift card ,free itunes gift card generator .these place are used for music player,play store,i phone,i pad,ios,and play store to get it free than visit here. itunes gift cards

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA