Sass in the Real World: book 1 of 4

A Sass Style Guide

With all of Sass' new found powers, the responsibility of code quality is even more paramount. Leaving code littered with unclear rule separations, randomly imported mixins and no clear use of extended placeholders will quickly decrease the readability, scaleability and maintainability of your code. This will also increase the sneering and aggravation of other developers on your team. Guaranteed.

While there are no guarantees that following a few simple best practices will make your code better, it will make it easer to read and maintain.

Nesting: don't go too deep

Earlier we discussed a core strength of Sass, this being it's ability to remove unnecessary repetition from your nested CSS selectors. Whereas CSS requires selectors to be duplicated, Sass does not.

In the following CSS example, the parent selector .block is repeated each time as the author nests additional selectors for specificity. This pattern continues to repeat itself with each additionally nested selector. The div, the ul and the li are repeated as the author finally reaches the p.

.block div { border: 1px solid black; }
.block div ul { width: 100%; float: left; }
.block div ul li { float: left; width: 100%; background: orange; }
.block div ul li p { font-weight: bold; line-height: 1.5em; }

Sass' indentation syntax allows for the author to simply indent the nested child selector without repeating it's parent. As shown in the following example, each additional indentation tells Sass to inherit the previously nested selector.

.block div
  border: 1px solid black
  ul
    width: 100%
    float: left
    li
      float: left
      width: 100%
      background: orange
      p
        font-weight: bold
        line-height: 1.5em

With SCSS, the principal is the same. Indentation is used to assist in readability of the code, but it's the semi-colons ; that are required to separate declarations. Curly-brackets { ... } are required for block separation and to designate selector nesting. Shown in the following example each newly nested selector is placed within a new set of curly-brackets { ... }.

.block {                /* .block opening bracket */
  div {                 /* div opening bracket */
    border: 1px solid black;
    ul {                /* ul opening bracket */
      width: 100%;
      float: left;
      li {              /* li opening bracket */
        float: left;
        width: 100%;
        background: orange;
        p {             /* p opening bracket */
          font-weight: bold;
          line-height: 1.5em;
        }               /* p closing bracket */
      }                 /* li closing bracket */
    }                   /* ul closing bracket */
  }                     /* div closing bracket */
}                       /* .block closing bracket */

Nesting is a powerful feature, but be mindful of the inception rule. It is easy to fall into this comfortable trap of using selector inheritance to mimic your markup structure in attempts to dominate the cascade as clearly was the argument in this 37Signals article. Succumbing to the pressures of specificity, you will find yourself in a CSS selector nightmare. Style rules will be extremely difficult to reuse and very fragile to edit.

A common rule of thumb, if you are thinking of nesting a fourth time, you should ask yourself, "Does this selector really requires this much specification?" Can the code be abstracted so it can be used more universally? In CSS, and even more-so in Sass, keeping your selectors shallow and properly extending declarations will increase portability and reusability of your code.

Let's take an opportunity to refactor the previous example. In Sass we can easily reduce the level of specificity by simply removing some of the indentation.

.block
  div
    border: 1px solid black
  ul
    width: 100%
    float: left
  li
    float: left
    width: 100%
    background: orange
  p
    font-weight: bold
    line-height: 1.5em

With SCSS we can accomplish the same, but SCSS requires you redefine your nesting by moving the curly-brackets { ... } as shown in the following example.

.block {
  div {
    border: 1px solid black;
  }
  ul {
    width: 100%;
    float: left;
  }
  li {
    float: left;
    width: 100%;
    background: orange;
  }
  p {
    font-weight: bold;
    line-height: 1.5em;
  }
}

Either Sass or SCSS, the following CSS output will be the same. The result, as shown, less nesting means shallower style rule definitions, better portability and faster code.

.block div { border: 1px solid black; }
.block ul { width: 100%; float: left; }
.block li { float: left; width: 100%; background: orange; }
.block p { font-weight: bold; line-height: 1.5em; }