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:
@function
s,@mixin
s, variable, list and map declarations and single-line comments do not render Sass.- CSS declarations and
@include
s 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: