CSS

Style and format

Property organization

Do your best to organize properties in related groups of functionality (such as the following), and sort them in this given order:

  1. Preprocessor specific directives, like @extends or @include;
  2. position and related properties like top, right, z-index and such;
  3. display and box-model related properties: height, width, padding, margin, box-sizing, visibility, etc;
  4. Font/text definitions (font-family and friends, line-height, text-decoration) and color;
  5. background and border related properties;
  6. Additional CSS3 properties like box-shadow, transform and such. Such grouping rules might be enough to most of the daily CSS you should face.

If a specific selector ends up with several properties, you might want to split these properties in smaller groups and use a blank line as a separator.

.buy-button {
  /* box model properties */
  display: block;
  width: 200px;
  padding: 5px 10px;
  margin: 10px auto 5px;

  /* tipography definitions */
  font-size: 1.1em;
  color: #FFF;
  font-weight: bold;
  text-decoration: none;
  text-shadow: -1px 0 1px rgba(0,0,0,0.6);

  /* background and borders */
  background-color: #CA501F;
  background-image: linear-gradient(to top, #CA501F, #E57E56);
  border: 1px solid #CA501F;

  /* Additional properties */
  border-radius: 3px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
  transition: opacity .3s ease;
}

In case of complex definitions and long list of properties, consider splitting up groups of related styles into different selectors and applying multiple classes to the same element.

Naming conventions

Documentation

CSS isn't the most expressive language and requires a lot of knowledge of the existing domain and markup to understand the purpose of specific styles, how they should be used and what we can achieve with it. A good way to communicate these details about your code is to explain them with some bits of documentation.

As we have things like TomDoc to specify how we should document our Ruby code, here is a small specification on how to document stylesheets.

/* ==========================================================================
Main comment block

This can be used as a top level description block of your stylesheet,
explaning the purpose of the following styles and the subtle variations
that will be available. If your module/section/component requires a complex
markup structure you can always write down a small markup example below.

<div class='fancy-component'>
  <h2 class='fancy-component-title'>How you doing?</h2>
  <div class='fancy-component-body'>
    ...
  </div>
</div>

Modifiers:

An optional section that describes each modifier class that can be applied to
the component elements.

* is-hightlighed: Modifier for the 'fancy-component' element that emphasises
                  its contents.
* is-disabled:    Modifier for the 'fancy-component' element that disables the
                  action buttons inside it.
========================================================================== */

.fancy-component {
  /* ... */
}

.fancy-component.is-highlighted {
  /* ... */
}

.fancy-component.is-disabled {
  /* ... */
}

/* Sub section comment block
A sub section can be used to split big chunks of code and describe what
the following styles are about - you can use to document variations of
the core styles (a `much-more-fancy` variation of our `fancy-component`)
or secondary definitions of your code.
========================================================================== */
.fancy-component.much-more-fancy {
  /* ... */
}

/*
  Bullet lists can be useful to enumerate several details of a group
  of properties. Here is an example from https://github.com/necolas/idiomatic-css:

 * Grid container
 *
 * Must only contain `.cell` children.
 *
 * 1. Remove inter-cell whitespace
 * 2. Prevent inline-block cells wrapping
 */

.grid {
  height: 100%;
  font-size: 0; /* 1 */
  white-space: nowrap; /* 2 */
}

/* Or you can add just a simple remark, about an odd line or something very specific */

Preprocessors

Preprocessors like Sass, LESS or Stylus are useful for handling a large set of stylesheets and we should take note on a few details so we won't do bad use of these tools.

Linting

For linting your SCSS code, we recommend the use of the scss-lint gem, using this configuration as a starting point. For existing apps, feel free to change the configuration as you want to match the existing code style of the application if necessary.

$ gem install scss_lint # 'scss_lint', not 'scss-lint'
$ scss-lint app/assets/stylesheets/

If you want to lint your stylesheets whenever your application is built by a build agent, add the scss_lint to the test environment in your Gemfile and execute it together with your tests.

File organization

File organization should follow the size and complexity of the existing codebase and evolve as necessary, but the following pattern is recommended:

styles
├── application.scss
├── components
│   ├── # Project specific components.
├── support
│   ├── # Global functions, mixins, placeholders and variables.
├── vendor
│   ├── # 3rd party assets that aren't loaded through a package manager or the asset pipeline.
└── pages
    └── # Page specific styles, only when necessary.

Componentization

Most selectors should represent a module or component (both terms are similar, so it's safer to use only one term at a time) that is self contained in the codebase and reused across pages or sections of the application, without depending on the DOM hiearchy or any parent specific styles that are already in place.

Outside of components, we can have the following patterns of selectors:

Vendor prefixes

In case of using vendor prefixed properties and functions be sure to check browser compatibility at Can I use… to be sure of it and which prefixes you will need. Several CSS3 properties don't require vendor prefixes on several browsers, like border-radius and box-shadow. If you are not that lucky, place the vendor-prefixed properties before it's own unprefixed version.

  .button:hover {
    -moz-transform: background-position .2s ease;
    -ms-transform: background-position .2s ease;
    -o-transform: background-position .2s ease;
    -webkit-transform: background-position .2s ease;
    transform: background-position .2s ease;
  }

References

Parts of this guideline was based on several resources across the Internet, that might provide extra information on specific topics, different approaches for similar scenarios or unanticipated scenarios on this guideline.