Sass’s killer feature was truly the
@import statement. When a Sass file is
imported, all the variables and mixins defined previously are now available in
any subsequent imported file. So, it is very good practice to define a single
top-level stylesheet that you link to from the
<HEAD> of your page layout.
In a Rails implementation, this would likely be the
root file is then compiled into a CSS file of the same name. This file and its
subsequent imported partials I refer to as a pathway.
Although most sites do not require it, you may have more than one pathway. There are several reasons for this, but they are often one of these:
- An “admin” view with a different design from the main site
- A live style guide with all of its extra CSS used to present the guide itself
- A new design in progress, with a corresponding separate layout
- A new pathway with refactored Sass and corresponding layout
When Sass compiles a pathway, it runs line-by-line from the top to the bottom
in linear fashion, delving recursively into any additional Sass partials
referenced with an
@import statement. As Sass compiles the pathway, it loads
any variables, mixins, functions, placeholders and declarations into the global
namespace for that pathway. For example, if you define a variable at the top of
a pathway, it is available for use later in the pathway, including in other
files imported after the variable’s declaration.
@import partials from the codebase, therefore it is not uncommon
for two pathways to share a common partial. For example, if you needed the same
color palette variables in a new design you were working on, you might
_colors.scss partial in more than one pathway.
When naming Sass files, partials that are imported should begin with a leading underscore. This is mostly a convention to let developers know this is not a root Sass pathway file, and it is intended to be imported.
The important thing here is to understand that for a given Sass load path, the
namespace for declarations is global and the
@import statement propagates
those declarations down into the partials.
In a previous post Separate Rendering Sass From Non-Rendering Sass, I covered how and why to separate these types of Sass.
As I mentioned in that article, variables, functions, and mixins should be separated from Sass declarations that result in CSS being generated. Separating the two gives you:
- flexibility among Sass pathways,
- clarity among imports without redundancy,
- speed for the developer who may now assume access to all functions, variables, and mixins in a pathway
Let’s start with a simple setup that only separates rendering and non-rendering Sass.
+-- application.scss +-- base/ | +-- _colors.scss | +-- _grid-settings.scss | +-- _icon-variables.scss | +-- _variables.scss +-- patterns/ | +-- _cards.scss | +-- _posts.scss | +-- _layouts.scss | +-- _lists.scss | +-- ...
And the root Sass pathway file:
application.scss @import "base/colors"; @import "base/grid-settings"; @import "base/icon-variables"; @import "base/variables"; @import "patterns/cards"; @import "patterns/posts"; @import "patterns/layouts"; @import "patterns/lists";
base folder holds all the non-rendering Sass.
patterns folder holds all
the Sass declarations that will result in CSS. Whenever a new pattern is made,
the developer can safely assume they have access to any variable, mixin, or
function that exists.
Suppose you made an additional Sass pathway:
new_lander.scss @import "base/colors"; @import "base/grid-settings"; @import "base/icon-variables"; @import "base/variables"; @import "base/hero"; @import "base/signup-box";
Now your alternate layout and pathway has access to all of the variables, functions, and mixins from the other pathway.
Not all patterns need all variables, functions, and mixins. Isn’t this exposing too much?
True, not all patterns will use everything, but there is an unbalanced trade-off in favor of always keeping variables, mixins, and functions in the global scope.
- Easy creation of additional pathways.
- Developer never has to search to see if what they need is already imported,
which becomes difficult with
@importstatements in partials.
- Chances for naming conflict among variables, functions, and mixins are lowered because conflicts are addressed as they are built.
- No accidental duplicate
@importof rendered CSS being sent down to the browser.
- Very explicit root pathway file: you know what’s in there and what isn’t without having to go dig for it.
- Negligible performance impact (if you have compile-time performance
problems, try libsass or remove use of
@extendfrom deep nesting).