The file structure when using SCSS includes 4 folders: base, helpers, landmarks, and modules.
The base folder contains:
- Elements - styles for base element like
<body>
or<a>
. - Fonts -
@font-face
rules for embedding fonts for global use - Reset - common reset styles
The helpers folder contains:
- Utilities - styles for common patterns like
.isVisuallyHidden
and common mixins likeclearfix
- Variables - all global variables used throughout the site
- Vendor - mixins for vendor prefixes
The landmarks and modules folders contain:
- A folder for each object named after the object
- A file within each folder named after the object that contains relevant styles for the object
Additionally there is a screen.scss
file that is used to import all SCSS partials for inclusion in a single compiled screen.css
file.
└── assets
└── styles
├── base
| ├── _elements.scss
| ├── _fonts.scss
| └── _reset.scss
├── helpers
| ├── _utils.scss
| ├── _vars.scss
| └── _vendor.scss
├── landmarks
| ├── masthead
| | └── _masthead.scss
| ├── navPrimary
| | └── _navPrimary.scss
| └── footer
| └── _footer.scss
├── modules
| ├── blocks
| | └── _blocks.scss
| ├── grid
| | └── _grid.scss
| ├── hlist
| | └── _hlist.scss
| └── media
| └── _media.scss
└── screen.scss
When media queries are introduced into the code the folder structure becomes more complex in order to offer the modularity required to support legacy browsers.
The file structure remains the same, however the following rules apply.
- Each object in the landmarks or modules folder should use the name of the object and the name of the corresponding breakpoint in it's file name separated by a single underscore.
- If a module level variable is needed for multiple breakpoints, add a
_helpers.scss
partial. Use the aforementioned naming convention - the object name followed by_helpers.scss
Additionally, instead of compiling everything into a single screen.css
file, code will be compiled into modern.css
and legacy.css
files using the following steps:
- Create a
_screen_breakpoint.scss
file for each breakpoint - Import partials for each module into the corresponding breakpoint files making sure not to include media queries
- Import all breakpoint partials into
legacy.css
- Import all breakpoint partials into
modern.css
with each file contained inside the corresponding media queries
Taking these steps provides two production ready CSS files - one of which requires media queries and one that doesn't that can be used to apply a fixed width design for legacy browsers.
└── assets
└── styles
├── base
| ├── _elements.scss
| ├── _fonts.scss
| └── _reset.scss
├── helpers
| ├── _utils.scss
| ├── _vars.scss
| └── _vendor.scss
├── landmarks
| ├── masthead
| | ├── _masthead_large.scss
| | ├── _masthead_medium.scss
| | └── _masthead_screen.scss
| ├── navPrimary
| | ├── _navPrimary_large.scss
| | ├── _navPrimary_medium.scss
| | └── _navPrimary_screen.scss
| └── footer
| ├── _footer_large.scss
| ├── _footer_medium.scss
| └── _footer_screen.scss
├── modules
| ├── blocks
| | ├── _blocks_helpers.scss
| | ├── _blocks_medium.scss
| | └── _blocks_screen.scss
| ├── grid
| | └── _grid_medium.scss
| ├── hlist
| | ├── _hlist_helpers.scss
| | ├── _hlist_large.scss
| | ├── _hlist_medium.scss
| | ├── _hlist_screen.scss
| | └── _hlist_small.scss
| └── media
| └── _media_screen.scss
├── _screen.scss
├── _screen_large.scss
├── _screen_medium.scss
├── _screen_small.scss
├── legacy.scss
└── modern.scss
Sass files that are not intended to be compiled independently, should be named with a leading underscore.
_media.scss
Silent comments should be used when the comment is irrelevant to the output.
//----------------------------------------------------------------------
// Micro Clearfix Mixin
//----------------------------------------------------------------------
@mixin clearfix() {
&:before,
&:after {
content: " ";
display: table;
}
&:after {
clear: both;
}
}
Global Variables
Variables defined outside of ruleset are considered to be global and are used for setting values used across multiple modules, such as brand colors.
Define all global variables in the global helpers/_vars.scss
partial.
Write global variables using uppercase letters delimited by underscores.
$BRAND_COLOR_RED: #ff0000;
.nav a {
color: $BRAND_COLOR_RED;
}
Module Variables
Module variables are defined outside a ruleset and are intended for use only with a single module.
If the variable is used only in a single file, define it at the top of the file above all rulesets.
If the variable is used by more than one file in the module, define it in a module level _module_helpers.scss
partial.
To prevent variable collisions, module variables should be prefixed with the base object name separated by a single dash.
$example-SPACING_UNIT: 10px;
.example-hd {
margin-bottom: $example-SPACING_UNIT;
}
.example-bd {
margin-bottom: $example-SPACING_UNIT;
}
Private Variables
Private variables are defined inside a single ruleset and are intended for use only within that ruleset.
Write private variables using uppercase letters delimited by underscores, and preceded by a single underscore.
.exampleObject {
$_SIZE: 200px;
$_OFFSET: -($_SIZE / 2); // Pull the object half its size to center it.
position: absolute;
top: 50%;
left: 50%;
height: $_SIZE;
width: $_SIZE;
margin-top: $_OFFSET;
margin-left: $_OFFSET;
}
Operators should always be surrounded by a single space.
Use of operators should always be accompanied by a comment.
.exampleObject {
$_SIZE: 100px;
$_PULL: -($_SIZE / 2); /* Pull the object half its size to center it. */
position: absolute;
top: 50%;
left: 50%;
height: $_SIZE;
margin-top: $_PULL;
margin-left: $_PULL;
}
Avoid nesting selectors.
/* DO */
.hList {
@include clearfix();
}
.hList > li {
float: left;
}
/* DO NOT */
.hList {
@include clearfix();
> li {
float: left;
}
}
Also avoid nesting pseudo classes & pseudo elements.
/* DO */
.nav a {
color: #ffffff;
}
.nav a:hover {
color: #00ff00;
}
/* DO NOT */
.nav a {
color: #ffffff;
&:hover {
color: #00ff00;
}
}
There are a few scenarios where nesting is acceptable. These includes things like sandboxing an entire stylesheet to avoid conflicting selectors, wrapping a WYSIWYG stylesheet, and nesting media queries to make a small change that's not at a minor breakpoint.
When nesting is appropriate, all selectors should be indented one level deeper than the parent selector.
.exampleObject {
padding: 10px;
@media (max-width: 500px) {
padding: 20px;
}
}
Use mixins to define styles that can be reused throughout the site to avoid repeating common code blocks. Mixins can be used at both the global and module level. Mixins used by a single module should be prefixed with the module name, and defined in the appropriate location.
Mixin definitions should always include the parenthesis.
Provide default arguments when their absence could cause a compilation error, otherwise, avoid using default arguments in favor of optional arguments.
@mixin isVisuallyHidden() {
width: 1px !important;
height: 1px !important;
margin: -1px !important;
border: 0 !important;
padding: 0 !important;
clip-path: inset(100%) !important;
clip: rect(0 0 0 0) !important;
overflow: hidden !important;
position: absolute !important;
white-space: nowrap !important;
}
If a mixin is used to produce vendor prefixes of a single property, it should mimic the W3C naming and syntax.
@mixin transition($transition) {
-webkit-transition: $transition;
-moz-transition: $transition;
-o-transition: $transition;
transition: $transition;
}
Do not use @extend
.
/* DO */
.message {
padding: 10px;
border: 1px solid #cccccc;
}
.message_success { color: #00ff00; }
.message_error { color: #ff0000; }
/* DO NOT*/
.message {
padding: 10px;
border: 1px solid #cccccc;
}
.message_success {
@extend .message;
color: #00ff00;
}
.message_error {
@extend .message;
color: #ff0000;
}
@if
, @each
, @while
, @for
Flow control directives should never use the single line syntax.
Curly braces should be formatted identically to selectors.
.exampleObject {
@if 1 + 1 == 2 {
border: 1px solid;
}
}
@import
Do not include the file extension when using @import
.
@import "_media";
@media
It is acceptable to use @media
rules nested in selectors if they are used for small tweaks. Separate stylesheets (screen
, screen_small
, screen_large
, etc) should be used for major breakpoints.
.exampleObject {
padding: 10px;
@media (max-width: 500px) {
padding: 20px;
}
}
@function
Function naming should follow the same naming conventions as mixins.
@warn
It is acceptable to use @warn
in-lieu of TODO comments.
@debug
It is acceptable to use @debug
provided it is not committed to the version control repository.