Separate Rendering Sass From Non-Rendering Sass

Ward Penney

I always separate the Sass that renders CSS from the Sass that doesn’t. The benefits are subtle, but reach far into the future for the sustainability of the Sass codebase:

  • Expect access to all variables and mixins
  • Eliminate redundant declarations
  • Easily incorporate new layouts

Some Sass renders CSS, but some doesn’t:

  • @functions, @mixins, variable, list and map declarations and single-line comments do not render Sass.
  • CSS declarations and @includes do render Sass.

If you’re wondering about @extend, hang in there! It’s a special case I’ll cover later on.

The benefits of separation

When the non-rendering Sass is collected in one spot, you and your team members will appreciate several things:

Expect access to all variables and mixins

When writing Sass, it’s frustrating to discover that you don’t have access to a mixin or color variable you want declared in a pattern that is imported later. By establishing a best practice in the codebase to separate your non-rendering Sass and load it first, you will avoid this problem.

Eliminate redundant declarations

Sass’s killer feature was the @import statement, which enabled all of us to factor out our CSS into smaller files. However, without proper care the file structure can become unwieldy and messy. This happens often when rendering and non-rendering Sass are together and the maze of @import statements can be difficult to untangle.

By separating out your non-rendering Sass, you can now import it all in bulk over and over, and there won’t be any redundant CSS delivered to the user’s browser.

When CSS does render redundant declarations, its smallest impact is on CSS filesize. A medium-level impact is to the developers, who will struggle to scroll through extra junk in the styles inspector. At its worst, redundant rendering will tip you over the 4095 declaration limit in IE9.

Easily incorporate new layouts

For example, you may want a new layout (a new branded page, a mailer template or admin dashboard). To do this, you will likely make a second load path–a sister to application.scss. We want availability for all the standard things (colors, borders, typography, mixins, etc) but not to have to duplicate that code.

Building an alternate landing page

Let’s look at an example that creates an alternate landing page in a layout separate from the primary.

+-- application.scss
+-- application-alt.scss
+-- library/
|   +-- _colors.scss
|   +-- _grid-settings.scss
+-- patterns/
|   +-- _author-box.scss
|   +-- _footer.scss
|   +-- _header.scss
|   +-- _post.scss
+-- patterns-alt/
|   +-- _fancy-header.scss
|   +-- _testimonials.scss
|   +-- _pricing.scss

_colors.scss

$color-gray: rgb(192,199,206);
$color-black: rgb(35,31,32);
$color-white: rgb(252,253,253);
$color-predator-blood: rgb(157,254,56);

$color-brand-primary: $color-predator-blood;
$color-brand-secondary: $color-black;

Here, _colors.scss and _grid-settings.scss contain only non-rendering variable declarations.

application.scss

// Non-rendering
@import "library/colors";
@import "library/grid-settings";

// Rendering
@import "patterns/author-box";
@import "patterns/footer";
@import "patterns/header";
@import "patterns/post";

After we import the non-rendering Sass, next come the rendered patterns which now have access any variable defined in the non-rendering block.

application_alternate.scss

// Non-rendering
@import "library/colors";
@import "library/gird-settings";

// Rendering
@import "patterns-alt/fancy-header";
@import "patterns-alt/testimonials";
@import "patterns-alt/pricing";

Here, the non-rendering Sass is included again in the alternate layout, followed by the alternate patterns used only on the new landing page. You can now be confident that your alternate layout is not polluted by patterns from the old layout.

This is a small example with only one non-rendering file, but most projects will have many. Imagine how crazy it could get if this distinction is not made. In the future, when you codebase is much larger, you will be able to create a new load path with no problems and no refactor.

Strategies with @extend

For those of you that have used @extend before, classifying it as rendering or non-rendering is a difficult thing to do. Because @extend appends your current selector to the thing it’s extending, the distinguishing thing is about where it’s called, rather than where its target is defined.

Full disclosure: I’ve been getting away from @extend because of various reasons and I tend to place the code in the same pattern file in which they are referenced.

The placeholder selector in Sass

The percent sign % in Sass is called a placeholder selector. It is a way to make a declaration that won’t render right away, but can be extended later. So, technically, it is non-rendering Sass. However, I tend to consider placeholders declarations to be rendering Sass for two reasons:

  • The purpose of the placeholder is very similar to the purpose of a normal CSS declaration.
  • Any variables or mixins used in the placeholder (which is common in other declarations) will need all the non-rendering Sass to load first anyway.

So, IMO, it’s better to just keep it with the rendering patterns. I would never have a folder called extends/ because they are meaningful and should be named to the pattern they are defining.

Bourbon, Neat, Bitters and Refills

Let’s look at where the Bourbon Sass framework fits into the picture. Bourbon (A simple and lightweight mixin library for Sass) and Neat (A lightweight semantic grid framework for Sass and Bourbon) are comprised entirely of variables, functions and mixins. Because they do not render when imported, you can load Bourbon and Neat when you load non-rendering Sass and not worry about duplication!

Then if you choose, you can leverage Bitters (Scaffold styles, variables and structure for Bourbon projects) and Refills to get off the ground with a great toolbox of rendered patterns. Incorporate these two when you load your rendered Sass.

What’s next

Check out these selected articles to help you make the distinction between rendering and non-rendering Sass: