Sass & CSS Style Guide
A guide on how I author and organize style sheet files in websites and web applications.
Tools
My preferred CSS development environment consists of the following tools and methodologies:
- Sass preprocessor
- Gatsby with gatsby-plugin-sass for static sites
- Gulp with gulp-sass for WordPress websites
- SMACSS methodology
Folder structure
A typical project’s folder structure is based on recommendations on how to divide different types of styles in the SMACSS methodology.
- File and folder names are typically plural.
- Style base HTML elements within
bases/_elements.scss
. - Store general layout styles within
_layouts.scss
. - Modules should be stored in modules/. Use subfolders liberally to group related modules together.
- The end goal is to have Sass compile everything to a file called
styles.min.css
. Where this file is stored depends on the framework you’re using, how you configure your build tools, etc.
scss/
├─ bases/
│ ├─ _elements.scss
│ └─ _fonts.scss
├─ modules/
│ ├─ _footer.scss
│ ├─ _global-nav.scss
│ └─ _header.scss
├- non-modular/
│ └─ _home.scss
├─ vendor/
│ └─ font-awesome.scss
├─ _layout.scss
├─ _settings.scss
└─ style.scss
Asset manifest files
The file at scss/style.scss
should be used to tie all of the different bases,
layouts, modules, and other configurations together. Of course, create
additional manifest files if different parts of your website or application call
for it.
A typical asset manifest file will look like this:
// | |
// Fonts | |
// | |
@import "vendor/font-awesome"; | |
// | |
// Settings | |
// | |
@import "settings"; | |
// | |
// Vendor dependencies | |
// | |
@import "bower_components/bootstrap-sass/assets/stylesheets/bootstrap"; // Or whatever | |
// | |
// Bases | |
// | |
@import "bases/elements"; | |
// | |
// Layouts | |
// | |
@import "layouts"; | |
// | |
// Modules | |
// | |
@import "modules/headers", | |
"modules/global-navs", | |
"modules/footers"; | |
// | |
// Non-modular | |
// | |
@import "non-modular/home"; |
This file is split into several parts:
Fonts
Style sheets for embedding @font-face
declarations for web fonts.
Settings
Import Sass files containing global variables and mixins. Libraries like ZURB Foundation also have a global settings file that would be appropriate to include in this section.
Vendor Dependencies
Style sheets related to 3rd party libraries like ZURB Foundation, Twitter
Bootstrap, CSS resets, etc. When including the source code for the library
directly in a project, store the files in the appropriate vendor/
folder, or
include the files needed from the node_modules/
folder if you’re using
Yarn and/or NPM.
Bases
Styles for base elements without any class
or id
selectors.
Layouts
Styles for general layouts. If you have simple layout needs, you may be able to
store all layout styles in a single _layouts.scss
file in the root scss
folder.
Modules
Styles for individual modules.
Non-modular
A “junk drawer” of page-based styles. Contents in here should eventually be refactored into modules.
General formatting
I agree mostly with GitHub’s and Google’s general rules for CSS formatting.
Use soft-tabs with a 2 space indent.
tab
characters can end up displaying funkily in some contexts. Spaces are
consistent.
// Not recommended | |
.sosume { | |
color: #ccc; | |
font-size: rem-calc(11); | |
} | |
// Preferred | |
.sosume { | |
color: #ccc; | |
font-size: rem-calc(11); | |
} |
Strictly use class
names to style elements.
Only style via id
selectors when absolutely necessary (for example, if you’re
using 3rd party code that makes heavy use of id
s).
This keeps selectors mostly on even ground with regards to specificity.
Use lowercase for everything possible.
// Not recommended | |
color: #E5E5E5; | |
// Preferred | |
color: #e5e5e5; |
Avoid trailing whitespace at the ends of lines.
This causes issues with diffs in version control.
// Not recommended | |
.header { | |
background: #eee;_____ | |
} | |
// Preferred | |
.header { | |
background: #eee; | |
} |
Put spaces after :
in property declarations.
// Not recommended | |
.footer { | |
background:firebrick; | |
} | |
// Preferred | |
.footer { | |
background: firebrick; | |
} |
Put spaces before {
in rule declarations.
// Not recommended | |
.breadcrumbs{ | |
font-size: rem-calc(13); | |
} | |
// Preferred | |
.breadcrumbs { | |
font-size: rem-calc(13); | |
} |
Use hex color codes #000
unless using rgba
.
When possible, use the abbreviated 3-character version of the hex code.
// Not recommended | |
.global-navigation { | |
background: rgb(56, 128, 45); | |
color: #55bb00; | |
} | |
// Preferred | |
.global-navigation { | |
background: #123456; | |
color: #5b0; | |
} |
Use //
for comment blocks (instead of /* */)
.
Comments denoted by //
are hidden in the generated CSS, whereas /* */
are
passed along to the generated source.
Use hypens as word delimiters for class and id selectors unless the accompanying HTML markup requires otherwise.
The only main exception: inclusion of 3rd party libraries may require the use of
camelCase
, under_scores
, or no delimiters.
// Not recommended | |
.local_navigation {} | |
.localnavigation {} | |
.localNavigation {} | |
// Preferred | |
.local-navigation {} |
Sort directive names in alphabetical order.
// Not recommended | |
body { | |
padding: 0; | |
margin: 0; | |
background: #f5f5f5; | |
line-height: 1.2; | |
} | |
// Preferred | |
body { | |
background: #f5f5f5; | |
line-height: 1.2; | |
margin: 0; | |
padding: 0; | |
} |
Place @include
and @extend
directives as the first rules in a block of directives.
// Not recommended | |
.profile { | |
background: #dedede; | |
color: #3a3a3a; | |
@include border-radius(rem-calc(5)); | |
@extend .halo; | |
} | |
// Preferred | |
.profile { | |
@include border-radius(rem-calc(5)); | |
@extend .halo; | |
background: #dedede; | |
color: #3a3a3a; | |
} |
Any $variable
or @mixin
that is used in more than one file should be put in the bases/
folder.
Others should be put at the top of the file where they’re used.
As a rule of thumb, don’t nest further than 3 levels deep.
If you find yourself going further, think about reorganizing your rules (either the specificity needed or the layout of the nesting).
// Not recommended | |
.profile { | |
background: #dedede; | |
color: #3a3a3a; | |
.heading { | |
font-size: rem-calc(18); | |
a { | |
color: #00f; | |
&:hover { | |
color: lighten(#00f, 10%); | |
i { | |
line-height: 1; | |
} | |
} | |
} | |
} | |
} | |
// Preferred | |
.profile { | |
background: #dedede; | |
color: #3a3a3a; | |
} | |
.profile-heading { | |
font-size: rem-calc(18); | |
} | |
.profile-link { | |
color: #00f; | |
&:hover { | |
color: lighten(#00f, 10%); | |
i { | |
line-height: 1; | |
} | |
} | |
} |
Layouts
According to the SMACSS method, layout components are the major guiding elements on the page (e.g., headers, footers, sidebars).
My guidelines are similar to SMACSS:
- Prefix all layout class names with
l-
. For example,.l-two-columns
,.l-content
, and.l-sidebar
.
Because they are major components on the page, many layout styles will involve media queries and column width mixins. Here is a typical example for a mobile-first Foundation-based 2 column layout:
.l-two-columns { | |
@include grid-row; | |
} | |
.l-two-columns-content, | |
.l-two-columns-sidebar { | |
@include grid-column(12); | |
} | |
@media #{$large-up} { | |
.l-two-columns-content { | |
@include grid-column(9); | |
} | |
.l-two-columns-sidebar { | |
@include grid-column(3); | |
} | |
} |
Modules
Again, from SMACSS:
A Module is a more discrete component of the page. It is your navigation bars and your carousels and your dialogs and your widgets and so on. This is the meat of the page. Modules sit inside Layout components.
- Modules should be broken down into as small of units as possible.
- Prefix all module class names with the module name. For example,
.header
,.header-title
,.header-icon
, etc. for a header module. - Don’t rely on specifying HTML elements as module selectors. For example,
don’t do this:
.header li
. Instead, prefer.header-item
. - Avoid chaining together too many words in a module class name. Consider
changing verbose names like
.article-quote-header-title
to something shorter like.article-quote-title
. In this case, even consider styling asides separately in a.quote
module.
Related resources
- Sass preprocessor
- Gatsby
- gatsby-plugin-sass
- Gulp
- gulp-sass
- SMACSS
- GitHub CSS Styleguide
- Google HTML/CSS Style Guide
- Modular CSS, Chris Peters
Last updated on