55 Minutes

Welcome to the 55 Minutes blog.
55 Minutes is a web development consultancy in San Francisco building apps for design-led businesses and startups. On this blog we discuss the technology tools of our trade: Ruby on Rails, Django, Sass, OS X, and more.

SMACSS and Rails A Styleguide for 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 can we apply these principles using SCSS in a Rails 3.2 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 smacss.com. 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.

Categorization

Guidelines

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.

app/assets/stylesheets/
├── application.css.scss
├── base.css.scss
├── layout.css.scss
|
├── globals
│   ├── _all.css.scss
│   ├── _functions.css.scss
│   ├── _mixins.css.scss
│   └── _variables.css.scss
|
└── modules
    ├── alert.css.scss
    └── …

vendor/assets/stylesheets/
├── 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.

Sprockets and guard-livereload conventions dictate that we use the double extension of .css.scss. If you use just .scss, your stylesheets will still compile, but guard-livereload won’t work out of the box.2

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-starter 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-starter:

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

Notes

  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.

  2. For a complete walkthrough of using guard-livereload with Rails, check out my earlier post: Lightning-Fast Sass Reloading in Rails 3.2.

comments powered by Disqus