Intro

Every line of code should appear to be written by a single person, no matter the number of contributors.

Basic Editor Preferences

Set your editor to the following settings to avoid common code inconsistencies and dirty diffs:

  • Use soft-tabs set to 2 spaces. They're the only way to guarantee code renders the same in any environment.
  • Trim trailing white space on save.
  • Set encoding to UTF-8.
  • Add new line at end of files.

If you are using Sublime Text 2, have a look at these settings.

Best Practices

  • Strive to maintain HTML standards and semantics, but not at the expense of practicality. Use the least amount of markup with the fewest intricacies whenever possible.
  • Break down CSS into modular components instead of pages. Pages can be rearranged and components moved.
  • Restirct the number of dependencies required. Any code maintained by a third-party has the potential to cause inconsistencies in your own code.
  • Think and work with progressive enhancement in mind at all times.
  • Comment your code whenever possible, even if it seems excessive, cumbersome or obvious at times. Your future self and fellow developers will thank you.

Preprocessors and Version Control

CSS and JS are processed using CodeKit, with the config.codekit file in the root managing the settings. Version control is handled via Git.


This guide was heavily inspired by @mdo's Code Guide.

HTML

Syntax

  • Use soft-tabs set to 2 spaces.
  • Nested elements should be indented once (2 spaces).
  • Always use double quotes, never single quotes, on attributes.
  • Don't include a trailing slash in self-closing elements.
  • Don’t omit optional closing tags.
  • As per the HTML5 spec, there is no need to specify a type when including CSS and JavaScript files.
  • Whenever possible, avoid superfluous parent elements when writing HTML. Many times this requires iteration and refactoring, but produces less HTML.

Attribute Order

For easier reading/scanning of code always declare the classes of the element first.

Group further attributes as it makes most sense to you.


<section class="section" role="main">

<div class="address" itemscope itemtype="http://schema.org/PostalAddress">

<img class="img" src="" alt="" role="presentation" aria-hidden="true" >

<input
  class="form__field"
  name="number"
  id="number"
  type="text"
  placeholder="1122"

  aria-required="true"
  required
  data-msg-required="Please add a number."
  data-rule-digits="true"
  data-msg-digits="Please enter only numerical characters."
>

CSS

CSS is written in Sass.

Sass files are combined to styles.min.css.

Bourbon is used as a library for common mixins.

CSS is written following the mobile-first approach, declaring styles for small viewports first and then making adjustments for larger viewports.


/* Default style */
h1 {
font-size: 20px;
}
/* Larger viewport - using Media Query with Sass Variable */
@media screen and (min-width: $breakpoint) { {
  h1 {
    font-size: 26px;
  }
}

File organization


css/
|
|-- 01tools/                   # Global tools
|   |-- helpers.scss           # Helper classes and mixins
|   |-- mixins.scss            # Sass mixins
|   |-- variables.scss         # Sass variables, incl. colours, fonts etc.
|
|-- 02base/                    # Base styles
|   |-- normalize.scss         # Help with cross-browser consistency
|   |-- typography.scss        # Unclassed and some classed styled
|
|-- 03modules/                 # Global reusable components
|   |-- icons.scss             # Icons
|   |-- forms.scss             # Forms and form elements
|   |-- media.scss             # Images, videos etc
|   ...
|
|-- 04layout/                  # Page styles (add file for every page needed, but keep them to minimum)
|   |-- global.scss            # Global layout styles
|   |-- sitefooter.scss        # Site’s header
|   |-- siteheader.scss        # Site’s footer
|
|-- 05pages                    # Page styles (add file for every page needed, but keep them to minimum)
|   |-- base.scss              # Global base page styles
|   |-- home.scss              # Home specific page
|   ...
|
|-- print.scss                 # Print styles
|-- styles.scss                # Main import file. Compiles to styles.min.css

Syntax

  • Use soft-tabs with 2 spaces.
  • When grouping selectors, keep individual selectors to a single line.
  • Include one space before the opening brace of declaration blocks.
  • Place closing braces of declaration blocks on a new line.
  • Include one space after : for each declaration.
  • End all declarations with a semi-colon.
  • Comma-separated property values should include a space after each comma (e.g. box-shadow).
  • Decide on whether you using upper or lower case for hex values and keep it consistent across all styles.
  • Double-quote attribute values in selectors, e.g., input[type="text"].
  • Don't specify units for zero values, e.g. margin: 0; instead of margin: 0px;.

/* Bad CSS */
.selector, .selector-secondary, .selector[type=text] {
padding:15px;
margin:0px 0px 15px;
box-shadow:0 1px 2px #CCC,inset 0 1px 0 #ffffff
}

/* Good CSS */
.selector,
.selector-secondary,
.selector[type="text"] {
padding: 15px;
margin: 0 0 15px;
box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;
}

Avoid shorthand conventions

Avoid using shorthand declarations as it leads to sloppier code with the need to add unnecessary overrides.

Although some people may feel declaring properties singularly is too verbose, it is far easier to manage when multiple developers are managing the code.


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

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

Ideal declaration order

  1. Positioning
  2. Box-model
  3. Visual
  4. Typographic
  5. Misc

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

/* Box-model */
box-sizing: border-box;
display: block;
float: right;
padding: 50px;
margin: 50px;
border: 3px;
width: 100px;
height: 100px;

/* Visual */
background-color: #f5f5f5;
border-radius: 3px;

/* Typography */
font: normal 13px Arial, sans-serif;
line-height: 1.5;
color: #333;
text-align: center;

/* Misc */
opacity: 1;
}

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.

Breakpoints are declared in ems, here’s why. Use Bourbon’s 'Pixels to Ems' function to help.


@media screen and (min-width: em(640px)) {
  .element { ... }
  .element--selected { ... }
}

Class Names

  • Keep classes lowercase (no camelCase).
  • Follow the BEM principles for class names, using two dashes for modifier classes and two underscores for child elements.
  • Avoid arbitrary shorthand notation.
  • Use meaningful names; use structural or purposeful names over presentational.

/* Bad example */
.t { ... }
.small { ... }
.item { ... }

/* Good example */
.tweet { ... }
.tweet--small { ... } /* modifier class */
.tweet__item { ... } /* child element */

Nesting

Avoid unnecessary element nesting. Consider nesting only if you must scope styles to a parent and if there are multiple elements to be nested. However, this should be very rarely needed, if at all.

When working with modules, you can use Sass’ ampersand feature to nest modifier and child declarations, which can help to organise blocks of code without creating verbose declarations as an end result.


/* Input */
.tweet {
  &--small { ... }

  &__item { ... }
}

/* Output */
.tweet { ... }
.tweet__item { ... }
.tweet--small { ... }

JavaScript

Separation of Concerns

JavaScript behaviour should never be linked to classes. By using classes as styling hooks only and the data-js attribute for JS behaviour only, we are preventing any possibility of the two ever crossing streams. Any changes to classes will never affect the JS behaviour and vice versa. This post explains this concept and its advantages well.


<section class="tabs__section" data-js="tabs-section">
  <h2 class="tabs__section__heading" data-js="tabs-section-trigger">
    Description
  </h2>
  <div class="tabs__section__content" data-js="tabs-section-content">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Hic cupiditate corporis molestias, fugiat cumque non veritatis dolorem laborum laudantium recusandae consectetur eos itaque facilis obcaecati consequuntur error cum. Aliquam repellendus nam, minima! Placeat est rerum iure enim quis commodi, aut tenetur dolorum eius quae. Accusantium repudiandae enim repellendus veritatis, iste.</p>
  </div>
</section>

File Organization


js/
|
|-- libs.js         # Includes any third-party scripts, minifies into libs.min.js.
|-- global.js       # Global site functions, minifies into global.min.js.
|-- styleguide.js   # This guide’s JS, minifies into styleguide.min.js.
|
|-- # Add more JS files as required for specific sections of the site, i.e. 'home.js'

Syntax

  • Use soft-tabs set to 2 spaces.
  • Nested elements should be indented once (2 spaces).
  • Always use single quotes for selectors.

/* HTML */
<button data-js="slidein-toggle">Toggle me</button>

/* JS */
function slideInContent() {
  var $slideToggleBtn = $('[data-js="slidein-toggle"]');
  ...
}

Colours

01tools/colours.scss
Colour Sass HEX
$grey #253D40
$greyLighter #516466
$greyLightest #99A6AD
$yellow #FFB703
$pink #F2385A
$blue #4AD9D9

Helpers

01tools/helpers.scss

Helpers are classes and mixins. The classes can be applied to elements in the HTML or used as @extends.

Some of them also exist as @mixins, so that they can be included within media queries.


.sr-only, @mixin sr-only

Hides an element but keeps it available for screen readers.

.clearfix, @mixin clearfix

Contain floating elements to ensure following elements aren't floated around them.

.inline-block, @mixin inline-block

Cross-browser inline-block display, that also works on IE7 and below. Vertically aligns items to top.

.maxwidth595, .maxwidth980

Set max-width for element and vertically centers it.

List modifiers

  • .list--nobull, removes bullets/numbers from list elements.
  • .list--inline, inlines list items.

Text modifiers

  • .text--center, centers text.
  • .text--upper, uppercases text.

Mixins

01tools/mixins.scss

A couple of custom mixins, which are not covered by Bourbon and are not classed as styling helpers.

REM Mixin

Converts pixel units into both pixel and rem values. Adapted from Ben Frain’s code.


/* rem(font-size, 28px) returns: */
font-size: 28px;
font-size: 1.75rem;

If you are using Sublime Text and Emmet, consider adding these following custom snippets to Emmet customization section in the Settings - User file to make your life easier:


  "css": {
    "snippets": {
      "rem": "@include rem(${1});",
      "remm": "@include rem(margin, ${1});",
      "remmt": "@include rem(margin-top, ${1});",
      "remmr": "@include rem(margin-right, ${1});",
      "remmb": "@include rem(margin-bottom, ${1});",
      "remml": "@include rem(margin-left, ${1});",
      "rempt": "@include rem(padding-top, ${1});",
      "remp": "@include rem(padding, ${1});",
      "rempr": "@include rem(padding-right, ${1});",
      "rempb": "@include rem(padding-bottom, ${1});",
      "rempl": "@include rem(padding-left, ${1});",
      "remw": "@include rem(width, ${1});",
      "remmw": "@include rem(max-width, ${1});",
      "remh": "@include rem(height, ${1});",
      "remmh": "@include rem(max-height, ${1});",
      "remfz": "@include rem(font-size, ${1});",
      "remlts": "@include rem(letter-spacing, ${1});",
      "remt": "@include rem(top, ${1});",
      "remr": "@include rem(right, ${1});",
      "remb": "@include rem(bottom, ${1});",
      "reml": "@include rem(left, ${1});"
    }
  }

Hover States

A shortcut to apply styling changes to the &:hover, &:focus, &:active states in one go.


a {
  color: blue;

  @include hover-states {
    color: red;
  }
}

Typography

02base/typography.scss

This Is a Heading 1

Sed ut perspiciatis bold text sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. italised text voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem small text.

This Is a Heading 2

This Is a Heading 3 That Spans over Multiple Lines This Is a Heading 3 That Spans over Multiple Lines This Is a Heading 3 That Spans over Multiple Lines

Sed ut perspiciatis unde subscript text sit voluptatem accusantium doloremque subscript text, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim inline text link quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione deleted text.

This Is a Heading 4

An abbreviation: WWF.


Lists

Unordered List

  • Blue Arrow fraud Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, nobis maxime maiores ad cupiditate quibusdam tempora iste magni quos eius eligendi rerum sapiente a ut nisi officia ratione. Sit, sunt est ab id eos natus ratione a odit quia quam! Molestiae, maiores repellat assumenda voluptate excepturi voluptatum necessitatibus blanditiis sit.
  • Maxwell brothers fraud
  • Jubilee line fraud
  • Microsoft fraud
    • A nested list
    • A nested list
  • Wickes fraud
  • London City Bond fraud

Ordered List

  1. List item
  2. List item
    1. A nested list
    2. A nested list
  3. Another item which has a bit more text Another item which has a bit more text Another item which has a bit more text

Definition Lists

Coffee
- black hot drink
Milk
- white cold drink

Quotes

Blockquote

One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.

Franz Kafka

One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.

Franz Kafka

Short Quote

One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.

Page Intro

03modules/page-intro.scss
I transform designs into user-friendly and successful websites.

<div class="page-intro">
  I transform designs into user-friendly and successful websites.
</div>

Page Heading

03modules/page-heading.scss

Sustainable Food City

June 2015

<header class="page-heading">
  <h1 class="page-heading__heading">Sustainable Food City</h1>
  <span class="page-heading__subheading">June 2015</span>
</header>

Media

03modules/media.scss

Images

An image caption.

Videos

Never Gonna Give You Up.

<figure>
  <img src="http://placehold.it/980x550" alt="">
  <figcaption>
    An image caption.
  </figcaption>
</figure>

<figure>
  <div class="video-wrapper">
    <iframe width="1280" height="720" src="https://www.youtube.com/embed/dQw4w9WgXcQ?wmode=transparent&showinfo=0" frameborder="0" allowfullscreen></iframe>
  </div>
  <figcaption>
    Never Gonna Give You Up.
  </figcaption>
</figure>

Code Blocks

03modules/code.scss

When using code blocks, ensure that the prism.css and prism.js files are included on the page/template.


<pre class="language-markup maxwidth980"><code>
<p>When using code blocks, ensure that the prism.css and prism.js files are included on the page/template.</p>
</code></pre>

Icon Panels

03modules/icon-panels.scss

User-Centred Development

I really do believe that the web is for everyone and will always do my best to be the users’ advocate. This means my focus throughout design reviews and site builds will lie with accessibiliy, progressive enhancements, responsive techniques, and optimising performance.

Modular CSS

I love taking designs apart into components and then convert those into streamlined, modular code. For most projects, I will start by coding up a well-documented comprehensive style guide. With this and detailed planning, the 'puzzle pieces' can easily fall into place and integrate with the back-end. It also ensures that the site remains maintainable and extendable.


<div class="icon-panels">
  <div class="icon-panels__item">
    <img class="icon-panels__item__icons" src="/assets/images/icons-usercentred.svg" onerror="this.src='/assets/images/icons-usercentred.png';this.onerror=null" alt="" role="presentation" aria-hidden="true">
    <h2 class="icon-panels__item__heading">
      User-Centred Development
    </h2>
    <p>...</p>
  </div>
  <div class="icon-panels__item">
    <img class="icon-panels__item__icons" src="/assets/images/icons-modular.svg" onerror="this.src='/assets/images/icons-modular.png';this.onerror=null" alt="" role="presentation" aria-hidden="true">
    <h2 class="icon-panels__item__heading">
      Modular CSS
    </h2>
    <p>...</p>
  </div>
</div>

Projects Listing

03modules/projects.scss

<ul class="projects">
  <li class="projects__item">
    <article>
      <a href="">
        <img class="projects__item__img" src="http://placehold.it/800x600" alt="" role="presentation" aria-hidden="true">
        <h2 class="projects__item__heading">Department Store for the Mind</h2>
      </a>
    </article>
  </li>
  ...
</ul>

Notes Listing

03modules/notes.scss

<ul class="notes">
  {% for entry in entries %}
    <li class="notes__item">
      <article itemscope itemtype="http://schema.org/BlogPosting">
        <a href="{{ entry.url }}" itemprop="url">
          <h2 itemprop="headline">{{ entry.title }}</h2>
          <time class="page-heading__subheading" datetime="{{ entry.postDate|date('Y-m-d') }}" itemprop="datePublished">
            {{ entry.postDate|date('jS F Y') }}
          </time>
          <p>{{ entry.pageIntro }}</p>
        </a>
      </article>
    </li>
  {% endfor %}
</ul>

Prev/Next Links

03modules/prev-next.scss

{% set entries = craft.entries.section('projects') %}
{% set prevEntry = entry.getPrev(entries) %}
{% set nextEntry = entry.getNext(entries) %}
<div class="prev-next">
  {% if prevEntry %}
    <a class="prev-next__link" href="">
      <i class="icon icon--arrow-left" aria-hidden="true"></i>
      <span class="sr-only">Previous project: </span>{{ prevEntry.title }}
    </a>
  {% endif %}
  {% if nextEntry %}
    <a class="prev-next__link prev-next__link--next" href="">
      <span class="sr-only">Next project: </span>{{ nextEntry.title }}
      <i class="icon icon--arrow-right" aria-hidden="true"></i>
    </a>
  {% endif %}
</div>