Kleenheat SASS Style Guide

Kleenheat uses Sass to generate its style sheets. This guide describes the conventions we follow when creating Sass files.

These guidelines are organized as simple recommendations prefixed with the terms DO, CONSIDER, AVOID, and DO NOT.

1. Style Sheets

1.1 Application Files

DON’T use a single style sheet for an application.

<link rel="stylesheet" href="/-/styles/everything.css" />

DO use a small number of style sheets, including the Global style sheet, an application style sheet, and, if needed, microsite or component style sheets.

<link rel="stylesheet" href="/-/styles/global.css" />
<link rel="stylesheet" href="/-/styles/my-account.css" />
<link rel="stylesheet" href="/-/styles/sign-up.css" />

1.2 Files

DO use a separate file for each component.

DO start each SASS file with a comment providing its name, and ideally with a description and an example of its use.

/*
 * Cards
 *
 * A card encloses related content in a box.
 *
 * Example:
 *    <div class="card">
 *      <div class="card-header"></div>
 *      <div class="card-body"></div>
 *      <div class="card-footer"></div>
 *    </div>
 */

DO start each root stylesheet by declaring UTF-8 as its string encoding.

/*
 * Global
 *
 * Comprises styling which applies across all Kleenheat web applications.
 */

@charset "UTF-8";

DON’T include any rules in a root stylesheet—it should only comprise links to partial files.

/*
 * Global
 *
 * Comprises styling which applies across all Kleenheat web applications.
 */

@charset "UTF-8";

/* Setup */
@import "global/functions";
@import "global/mixins";
@import "global/variables";

/* Style sheet */
@import "global/reset";
@import "global/layout";
@import "global/miscellaneous";
/*
 * Global
 *
 * Comprises styling which applies across all Kleenheat web applications.
 */

@charset "UTF-8";

/* DO NOT include variables */
$use-dark-background: false;
$use-custom-fonts:    true;

/* Setup */
@import "global/functions";
@import "global/mixins";
@import "global/variables";

/* Style sheet */
@import "global/reset";
@import "global/layout";
@import "global/miscellaneous";

/* DO NOT include rules */
body.override {
    background: #ccc;
}

2. Layout

2.1 Braces

DO follow the Kernighan and Ritchie style (Egyptian Brackets) for blocks.

.card {
    background-color: $card-bg;
    border: solid 1px $card-border-color;

    .card-body {
        padding: $card-content-padding;
    }

    .card-footer {
        padding: 0 $card-content-padding;
    }
}

DO wrap a single-line block of code in braces.

.medium {
    max-width: $grid-breakpoint-medium;
} 

CONSIDER keeping single-line blocks on one line where it helps readability.

> .col-1 { flex: 1; }
> .col-2 { flex: 2; }
> .col-3 { flex: 3; }
> .col-4 { flex: 4; }

2.2 Lines

DO write only one statement per line.

.foo {
    display: block;
    overflow: hidden;
    padding: 0 1em;
}
.foo {
    display: block; overflow: hidden;
    padding: 0 1em;
}

DO use an 80-character line length wherever possible.

2.3 Indenting

DO use four spaces as indentation.

CONSIDER using more than four spaces for indentation where it helps readability.

.card {
    -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16);
            box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16);
}

2.4 Spacing

DO use a space after the colon in a property-value pair.

.foo {
    display: block;
}
.foo {
    display:block;
}

DO use a space after each comma in a list.

.foo {
    color: rgba(0, 0, 0, 0.16);
}
.foo {
    color: rgba(0,0,0,0.16);
}

2.5 The Ineption Rule

AVOID nesting rules more than four levels deep (the Ineption Rule).

body {
  div.container {
    div.content {
      div.articles {
        & > div.post {
          div.title {
            h1 {
              a {
              }
            }
          }
          div.content {
            p { ... }
          }
          div.author {
            p {
              a { ... }
            }
          }
        }
      }
    }
  }
}

3. General

3.1 Style Like You Mean It

DO follow the recommendations to style like you mean it.

3.2 Elements

DO use HTML5 elements and attributes and create styling rules that target elements and attributes rather than classes.

<!-- HTML -->
<form>
  <fieldset>
    <label for="name">Name</label>
    <input type="text" id="name" name="name" />
  </fieldset>
  <p>
    <button type="submit">Submit</button>
  </p>
</form>

/* CSS */
form {
  fieldset { ... }
  label { ... }
  [type="text"] { ... }
  [type="submit"] { ... }
}
<!-- HTML -->
<form class="form">
  <fieldset class="form-group">
    <label for="name" class="form-label">Name</label>
    <input type="text" id="name" name="name" class="form-control form-control-textbox" />
  </fieldset>
  <p>
    <button type="submit" class="form-button-submit">Submit</button>
  </p>
</form>

/* CSS */
.form {
  .form-group { ... }
  .form-label { ... }
  .form-control-textbox { ... }
  .form-button-submit { ... }
}

3.3 Roles

DO use ARIA roles and create styling rules that target roles rather than classes.

<!-- HTML -->
<body>
  <header role="banner"></header>
  <main role="main"></main>
  <footer role="contentinfo"></footer>
</body>

/* CSS */
[role="banner"] { ... }
[role="main"] { ... }
[role="contentinfo"] { ... }
<!-- HTML -->
<body>
  <header class="page-header"></header>
  <main class="page-content"></main>
  <footer class="page-footer"></footer>
</body>

/* CSS */
.page-header { ... }
.page-main { ... }
.page-footer { ... }

3.4 States

DO use ARIA attributes rather than classes to indicate states.

<!-- HTML -->
<nav role="navigation">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about" aria-current="page">About</a></li>
    <li><a href="/contact">Contact Us</a></li>
  </ul>
</nav>

/* CSS */
[role="navigation"] {
    [aria-current="section"] { ... }
}
<!-- HTML -->
<nav>
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about" class="is-active">About</a></li>
    <li><a href="/contact">Contact Us</a></li>
  </ul>
</nav>

/* CSS */
nav {
    .is-active { ... }
}

3.5 Microdata

CONSIDER using microdata rather than classes to target items.

<!-- HTML -->
<dl itemscope itemtype="http://schema.org/Person">
  <dt>Name</dt>
  <dd itemprop="name">Daffy Duck</dd>
  <dt>Email</dt>
  <dd itemprop="email">[email protected]</dd>
</dl>

/* CSS */
dl {
    [itemprop="name"] {
        font-size: 1.5rem;
    }
}
<!-- HTML -->
<dl>
  <dt>Name</dt>
  <dd class="name">Daffy Duck</dd>
  <dt>Email</dt>
  <dd class="email">[email protected]</dd>
</dl>

/* CSS */
dl {
    .name {
        font-size: 1.5rem;
    }
}

3.6 Data Attributes

DON’T write styling which targets data attributes.

<!-- HTML -->
<article data-columns="3" class="columns-3">
  <div></div>
  <div></div>
  <div></div>
</article>

/* CSS */
article {
    &.columns-3 > div { width: 33%; }
}
<!-- HTML -->
<article data-columns="3">
  <div></div>
  <div></div>
  <div></div>
</article>

/* CSS */
article {
    &[data-columns="3"] > div { width: 33%; }
}

3.7 Classes

AVOID using a class unless there is no HTML5 element or attribute, no ARIA role or attribute, and no microdata which would be suitable. This should only be the case for style elements with no semantic meaning, such as positoning elements and “hooks” for icons or modifiers.

<!-- HTML -->
<header role="banner">
  <div class="nav-wrapper">
    <nav role="navigation">
      <ul>
        <li class="home"><a href="/">Home</a></li>
        <li><a href="/about" class="about" aria-current="page">About</a></li>
        <li><a href="/contact" class="contact">Contact Us</a></li>
      </ul>
    </nav>
  </div>
</header>

/* CSS */
[role="banner"] {
    .nav-wrapper { /* positioning */ }
    [role="navigation"] {
        .home a    { /* icon */ }
        .about a   { /* icon */ }
        .contact a { /* icon */ }
    }
}

4. Comments

4.1 Notes

CONSIDER using numbered notes within comments.

/**
 * Radios and Checkboxes
 *
 * Notes:
 *   1. Add the correct box sizing in IE 10-
 *   2. Remove the padding in IE 10-
 */

input[type="radio"],
input[type="checkbox"] {
    box-sizing: border-box; /* 1 */
    padding: 0; /* 2 */
}

5. Naming

5.1 Language

DO use American English for naming variables.

$color
$centered
$normalized
$colour
$centred;
$normalised;

5.2 No BEM!

DON’T use the Block Element Modifier method for naming variables. Read Style like you mean it to recognise that HTML5 and ARIA specifications already provide many blocks, elements, and modifiers, leaving us needing only lightweight classes to fill any gaps.

<div class="card primary">
    <div class="card-body spaced emphasized">
        <ol>
            <li>...</li>
        </ol>
    </div>
</div>
<div class="card card--primary">
    <div class="card__body card__body--spaced card__body--emphasized">
        <ol class="card__ol">
            <li>...</li>
        </ol>
    </div>
</div>

5.3 States

DON’T use hyphens to create a state modifier, simply use the state modifier.

<div class="accordion">
  <div class="panel"></div>
  <div class="panel is-open"></div>
  <div class="panel"></div>
</div>
<div class="accordion">
  <div class="panel"></div>
  <div class="panel panel--is-open"></div>
  <div class="panel"></div>
</div>

5.4 JavaScript “Hooks”

DO use js- to prefix any class names which exist only as JavaScript “hooks”.

<p>Read our <a href="/terms-conditions" class="js-modal">terms and conditions</a>.</p>

5.5 Attribute Selectors

DO use quotation marks (") when using an attribute as a selector.

[role="banner"] { ... }
input[type="radio"] { ... }
[role='banner'] { ... }
input[type='radio'] { ... }
[role=banner] { ... }
input[type=radio] { ... }

6. Values

6.1 Numbers

DO use a zero before values less than one.

.foo {
    left: -0.5rem;
    opacity: 0.5;
}
.foo {
    left: -.5rem;
    opacity: .5;
}

DON’T use units when the value is zero.

.foo {
    width: 0;
}
.foo {
    width: 0px;
}

CONSIDER using rem rather than em to size text and elements.

.foo {
    left: 10rem;
    margin: 2rem;
}

DO use parentheses to indicate calculations.

.foo {
    width: (100% / 3);
}

6.2 Strings

DO use a quotation mark (") rather than an apostrophe (') to define a string.

.foo {
    content: " ";
    background-image: url("...");
}
.foo {
    content: ' ';
    background-image: url('...');
}

6.3 Variables

CONSIDER using variables if a value is used in more than one rule.

$sidebar-width: 12rem;

.content {
    margin-right: $sidebar-width;
}

.sidebar {
    width: $sidebar-width;
}

DO follow follow the `$component-state-property-size` formula for consistent naming.

$link-disabled-color
$card-active-shadow-xs

6.4 URLs

DO use a quotation mark (") when defining a URL.

.foo {
    background-image: url("/-/images/tile.svg");
}
.foo {
    background-image: url('/-/images/tile.svg');
}
.foo {
    background-image: url(/-/images/tile.svg);
}