Applying SMACSS to Rails Projects

How to organize your stylesheets in the asset pipeline.

SMACSS is a great set of principles for organizing CSS rules into reusable modules; it makes a lot of sense for teams that are collaborating on large web applications. How do you apply these principles using SCSS in a Rails project?

If you’re already familiar with SMACSS, skip ahead to the Rails styleguide.

SMACSS principles

SMACSS (Scalable and Modular Architecture for CSS) is a set of CSS guidelines created and promoted by Jonathan Snook, who also offers an e-book of the same name. A generous portion of the book’s contents is available for free at If you aren’t already familiar with SMACSS, I highly recommend the book; it’s a quick read.

Let’s recap some core principles of SMACSS before we dive into the Rails implementation.

SMACSS categorizes styles as follows:

These practices are strongly recommended:

SMACSS versus Rails conventions

As an experienced Rails developer, you may notice that many of the SMACSS principles contradict what are typically considered best practices in Rails.

In short, should you choose to apply SMACSS principles to your Rails project, keep in mind that you will be breaking some Rails conventions. Proceed with caution!

A SMACSS styleguide for Rails projects

With all the SMACSS background out of the way, let’s get to the actual application of SMACSS to a Rails project, shall we?

File organization. Structure your asset pipeline directories as follows. This layout borrows some conventions from GitHub’s CSS styleguide.

├── application.css.scss
├── base.css.scss
├── layout.css.scss
├── globals
│   ├── _all.scss
│   ├── _functions.scss
│   ├── _mixins.scss
│   └── _variables.scss
└── modules
    ├── alert.css.scss
    └── …

├── normalize.css
└── …

Filenames. In Sass, a leading underscore indicates a partial, meaning the file should not be compiled into a standalone CSS file. SMACSS advocates designing modules that can be used independently, so use partials only for pure Sass constructs, like variable, function, and mixin definitions.

Files that can stand alone (e.g. modules) should be named with the double-extension .css.scss. Partials, on the other hand, should start with an underscore and end with just .scss. Starting with Rails 4.2, partials named with .css.scss will trigger a deprecation warning.

Application manifest. Use the Sprockets //=require syntax to specify how your styles should be merged into a single stylesheet in production. Here’s an example application.css.scss:

//= require normalize
//= require ./base
//= require ./layout
//= require_tree ./modules

Globals. The globals directory is for Sass functions, variables, and mixins that are truly global: that is, things that are shared across multiple files. If you have variables or mixins that are only used by a single module, define those in the module file itself. Don’t clutter your globals directory with single-use code.

It is a good practice to use global variables for typography, like these:

$serif: Georgia, serif;
$sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;

$title-font-size: 42px;
$headline-font-size: 26px;
$sub-headline-font-size: 20px;
$base-font-size: 16px;
$small-font-size: 13px;

$baseline: 25px;
$base-line-height: ($baseline/$base-font-size);

Consider combining all of your global imports with a globals/_all.css.scss partial that looks like this:

@import "./variables";
@import "./functions";
@import "./mixins";

Then in your base, layout, and module stylesheets, start off each stylesheet by importing all your globals:

@import "globals/all";

Sass import versus Sprockets require

When using Sass within the Rails asset pipeline, there are two ways to combine stylesheets: the Sass way (@import) and the Sprockets way (//=require). Both come in handy.

@import. By using the import syntax, you are instructing the Sass compiler to combine the Sass source code first, and then perform compilation. If your intention is to reuse global variables, functions, and mixins (or you want to use a third-party library like Bourbon) you must use @import. Likewise, if you want to use the Sass @extend keyword to combine CSS selectors across files, you’ll need to use @import for those files as well.

//= require. The require syntax is not to aid in compilation, but to define manifests used to merge files for production deployment. When require is used, Sprockets compiles your Sass source code first as independent stylesheets, and then merges the resulting CSS into a single file.

Benefits of require in development mode. The reason this styleguide suggests using require for application.css.scss is due to how Sprockets helpfully changes its behavior depending on whether Rails is running in development or production mode.

By using //=require, in development mode you’ll see this in your browser:

<link rel="stylesheet" href="/assets/normalize.css">
<link rel="stylesheet" href="/assets/base.css">
<link rel="stylesheet" href="/assets/layout.css">
<link rel="stylesheet" href="/assets/modules/alert.css">

Separate stylesheets make browser-based troubleshooting much easier. When using the WebKit inspector to trace style rules, now you can clearly see the cascade: which styles come from normalize, which are from base, your layout, and your modules.

Bootstrap your next project

If you like the suggestions that I’ve outlined in this post and are eager to apply SMACSS to your next Rails project, consider using my rails-template project on GitHub. Download the project tarball and use it as the foundation of your Rails app, or simply browse through the code and take what you need.

Here’s what you’ll find in my rails-template:

What’s been your experience integrating SMACSS and Rails? Let me know.

  1. Using presentational class names as advocated by SMACSS may feel wrong, especially since we were taught that well-written HTML and CSS should always be “semantic”. By following SMACSS, does that mean abandoning a clean separation between content and presentation? Isn’t that a bad thing? Not necessarily. Read Philip Walton’s excellent article on the subject: Defending Presentational Class Names