Code Guide

Standards for developing flexible, durable, and sustainable HTML, CSS, and JavaScript.

Table of contents

CSS

CSS

Syntax

Questions on the terms used here? See the syntax section of the Cascading Style Sheets article on Wikipedia.

/* Bad */
.selector, .selector-secondary, .selector[type=text] {
  padding:15px; margin:0px 0px 15px;
  background:rgba(0, 0, 0, 0.5) url("images/bg.png");
  box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF;
  font-family:"Open Sans",Verdana,sans-serif
}

/* Good */
.selector,
.selector-secondary,
.selector[type='text'] {
  margin-bottom: 15px;
  padding: 15px;
  background: rgba(0,0,0,0.5) url(images/bg.png);
  box-shadow: 0 1px 2px #ccc, inset 0 1px 0 white;
  font-family: 'Open Sans', Verdana, sans-serif;
}

Comments

Code is written and maintained by people. Ensure your code is descriptive, well commented, and approachable by others. Great code comments convey context or purpose. Do not simply reiterate a component or class name.

Be sure to write in complete sentences for larger comments and succinct phrases for general notes.

/* Bad */
/* Modal header */
.modal-header {
  
}

/* Good */
/* Wrapping element for .modal-title and .modal-close */
.modal-header {
  
}

Class and ID names

These rules also apply when creating Sass and Less variable names.

/*
** Egregious. If you do this, next time
** you see me coming you better run.
*/
.margin-15 {  }
.float-right {  }

/* Bad */
.t {  }
.red {  }

/* Good */
.tweet {  }
.error {  }
<!-- Bad -->
<!-- You don't need both show-more and e-show-more -->
<a class="e-show-more show-more">Show more results…</a>

<!-- Good -->
<a class="show-more">Show more results…</a>

Declaration order

Related property declarations should be grouped together following the order:

  1. Layout
  2. Positioning
  3. Box model
  4. Visual
  5. Typography
  6. Content & animations

Layout and positioning come first because they can remove an element from the normal flow of the document and override box model related styles. The box model comes next as it dictates a component's dimensions and placement.

Everything else takes place inside the component or without impacting the previous two sections, and thus they come last.

For a complete list of properties and their order, please see my stylelint-order config.

stylelint-order is a plugin to the popular style linter stylelint, that enables you to check the order of your style declarations.

.declaration-order {
  /* Layout */
  display: block;
  float: left;

  /* Positioning */
  position: absolute;
  z-index: 100;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;

  /* Box model */
  margin: 0;
  border: 1px solid #e5e5e5;
  border-radius: 5px;
  padding: 20px;
  width: 100px;
  height: 100px;

  /* Visual */
  opacity: 1;
  color: #333;
  background: #f5f5f5 url(images/page-bg.png);
  box-shadow: 0 1px 2px #ccc, inset 0 1px 0 white;

  /* Typography */
  font-family: 'Helvetica Neue', sans-serif;
  font-size: 14px;
  line-height: 1.5;
  font-style: normal;

  /* Content & animations */
  cursor: pointer;
  transition: all 0.3s linear;
  text-align: left;
  white-space: nowrap;
  text-overflow: ellipsis;
}

White space

Use white space (newlines) to enhance readability:

  1. Between groups of property declarations as described in Declaration order
  2. Between a property declaration and a nested ruleset
  3. Between consecutive rulesets
/* Bad */
.dont-do-this {
  margin: 0;
  border: 1px solid #e5e5e5;
  .nested-block-01 {
    float: left;
  }
  .nested-block-02 {
    float: right;
    margin-left: 2em;
    text-align: right;
  }
}

/* Good */
.this-is-better {
  position: absolute;
  top: 0;
  right: 0;

  border: 1px solid #e5e5e5;
  padding: 20px;
  width: 100px;
  height: 100px;

  .nested-block-01 {
    text-align: right;
    font-weight: bold;
  }

  .nested-block-02 {
    font-size: 2em;
    line-height: 1.2;
    font-style: italic;
  }
}

Don't use @import

Compared to <link>s, @import is slower, adds extra page requests, and can cause other unforeseen problems. Avoid them and instead opt for an alternate approach:

For more information, read this article by Steve Souders.

<!-- Use link elements -->
<link rel="stylesheet" href="core.css">

<!-- Avoid @imports -->
<style>
  @import url(more.css);
</style>

NEVER USE !important. I MEAN IT.

In short, don't do it.

/* !important is bad, mmmkay? */
.error {
  color: red !important;
}

/*
** Instead, increase the specificity of your
** selector as necessary. This is easier to
** understand the consequences of, ergo more
** predictable.
*/
form .error {
  color: red;
}

Media query placement

Place media queries as close to their relevant rule sets whenever possible. Don't bundle them all in a separate stylesheet or at the end of the document. Doing so only makes it easier for folks to miss them in the future. Here's a typical setup.

.element {  }
.element-avatar {  }
.element-selected {  }

@media (min-width: 480px) {
  .element { }
  .element-avatar {  }
  .element-selected {  }
}

Prefixed properties

Don't use vendor prefixes in your CSS:

Instead, write your code without vendor prefixes and use a plugin like autoprefixer in your build pipeline.

/* Don't bother with prefixed properties */
.selector {
  box-shadow: 0 1px 2px rgba(0,0,0,.15);
}

Single declarations

In instances where a rule set includes only one declaration, keep the line breaks for better readability; your declarations will begin in the same column and be easier to scan.

/* Multiple declarations, one per line */
.sprite {
  display: inline-block;
  width: 16px;
  height: 15px;
  background-image: url(../images/sprite.png);
}

/* Treat single declarations the same as multiple declarations */
.span1 {
  width: 60px;
}

.span2 {
  width: 140px;
}

.span3 {
  width: 220px;
}

Shorthand notation

Strive to limit use of shorthand declarations to instances where you must explicitly set all the available values. Commonly overused shorthand properties include:

Oftentimes we don't need to set all the values a shorthand property represents. For example, HTML headings only set top and bottom margin, so when necessary, only override those two values. Excessive use of shorthand properties often leads to sloppier code with unnecessary overrides and unintended side effects.

That said, there is no denying that using shorthand properties is convenient. The rule here is to use judgement and avoid overzealously using shorthand properties, especially if you know you'll need to override them in part later.

The Mozilla Developer Network has a great article on shorthand properties for those unfamiliar with notation and behavior.

/* Bad */
.element {
  margin: 0 0 10px;
  background: red;
  background: url(image.jpg);
  border-radius: 3px 3px 0 0;
}

/* Good */
.element {
  margin-bottom: 10px;
  background-color: red;
  background-image: url(image.jpg);
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}

Selectors

/* Bad */
span {  }
.page-container #stream .stream-item .tweet .tweet-header .username {  }
.avatar {  }

/* Good */
.avatar {  }
.tweet-header .username {  }
.tweet .avatar {  }

Nesting in Less and Sass

Avoid unnecessary nesting. Just because you can nest doesn't mean you should. Consider nesting only if you must scope styles to a parent and if there are multiple elements to be nested. The consequence is needlessly long, less performant, overly specific selectors.

Also take care with &, the parent selector:

// Don't nest when it's not necessary
.module {
  .module-content {
    .no-data-message {
      font-size: 1.25em;
      line-height: 1.5;
      text-align: center;
    }
  }
}

// This will give you a selector that's only as long
// as it needs to be
.no-data-message {
  font-size: 1.25em;
  line-height: 1.5;
  text-align: center;
}

// Avoid un-nesting with &
.child {
  .parent & {
    // This is confusing and might not behave as expected
    // if .child happened to be nested in something else
  }
}

// This is better and more understandable
a {
  text-decoration: none;

  &:hover,
  &:active {
    text-decoration: underline;
  }
}

Operators in Less and Sass

For improved readability, wrap all math operations in parentheses with a single space between values, variables, and operators. Take special care to do this for shorthand properties.

// Bad
.element {
  margin: 10px 0 @variable*2 10px;
}

// Good
.element {
  margin: 10px 0 (@variable * 2) 10px;
}

Colors in Less and Sass

Don't ever use raw hex colors in Less and Sass. Define them with human-readable variable names and use those. Better yet, assign colors to variables indicating their semantic usage.

Using semantic color variables throughout your code is more readable and easier to change.

// Bad
.module {
  border: 1px solid #eee;
}


// Better
$light-grey: #eee;

.module {
  border: 1px solid $light-grey;
}


// Best
$light-blue: #def;
$light-grey: #eee;

// Now you can change this to $light-blue in one place,
// and it shows up everywhere $section-border is used. Boom!
$section-border: $light-grey;

.module {
  border: 1px solid $section-border;
}

Organization

An example file hierarchy:

basics/
├── _colors.scss
├── _typography.scss
└── _grid.scss
shared/
├── _foundation.scss
├── _forms.scss
├── _mixins.scss
├── _header.scss
├── _footer.scss
└── _nav.scss
_feature-1.scss
feature-2/
├── _sub-feature-a.scss
└── _sub-feature-b.scss
_feature-3.scss
/*-----[ messaging ]----------------------------------------
*/
/*----------[ alerts ]--------------------------------------
*/
.alerts {
  .message {
    &.error {
      
    }

    &.warning {
      
    }
  }
}

/*----------[ growl notifications ]-------------------------
| Some additional context, if necessary.
*/
.growl {
  .message {
    
  }
}