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:
@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.
When the non-rendering Sass is collected in one spot, you and your team members will appreciate several things:
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.
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.
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.
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
$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;
_grid-settings.scss contain only non-rendering
// 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.
// 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.
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.
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.
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.
Check out these selected articles to help you make the distinction between rendering and non-rendering Sass: