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:

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);
}
view raw soft_tabs.scss hosted with ❤ by GitHub

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 ids).

This keeps selectors mostly on even ground with regards to specificity.

Use lowercase for everything possible.

// Not recommended
color: #E5E5E5;
// Preferred
color: #e5e5e5;
view raw lowercase.scss hosted with ❤ by GitHub

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;
}
view raw hex_colors.scss hosted with ❤ by GitHub

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 {}
view raw hyphens.scss hosted with ❤ by GitHub

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;
}
}
}
view raw nesting.scss hosted with ❤ by GitHub

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

Last updated on