Skip to content

sass coding guidelines

David Sklář edited this page Nov 3, 2017 · 1 revision

Sass

Sass coding guidelines

Best practices and guidelines for writing sane, consistent, maintable and scalable Sass (CSS).

It's actualy a mash-up of these documents:

Table of Contents


General principles

  • Strictly enforce the agreed-upon style;
    All code should look like a single person typed it.
  • Optimize (minified) code for bytesize;
    but keep the source maintainable, readable and understandable first.

Table of contents


Syntax

Use SCSS syntax, there're many good reasons:

  • it's an extention of CSS syntax,
  • code is legible/easy to understand,
  • every valid CSS3 stylesheet is a valid SCSS file with the same meaning,
  • SCSS understands most CSS hacks and vendor-specific syntax.

Table of contents


Whitespace

  • Use whitespace to improve readability.
  • Be consistent across the entire source codebase.
  • Never mix spaces and tabs for indentation.

Install EditorConfig plugin to your editor/IDE to help maintain the basic whitespace conventions.
Otherwise set your IDE configuration according to project .editorconfig file.

Table of contents


Comments

Well commented code is extremely important. Take time to describe components, how they work, their limitations, and the way they are constructed. Don't leave others in the team guessing as to the purpose of uncommon or non-obvious code.

Comment style should be simple and consistent within a single code base.

  • Place comments on a new line above their subject.
  • Keep line-length to a sensible maximum, e.g., 80 columns.
  • Make liberal use of comments to break CSS code into discrete sections.
  • Use "sentence case" comments and consistent text indentation.
  • Use component skeleton to write down new Sass component.
  • Use SassDoc 1.x C-style comments (/** */) for custom Sass extends, functions and mixins.
// =============================================================================
// Section comment block (not rendered)
// =============================================================================

.section {}

// Sub-section comment block (not rendered)
// =============================================================================

.subsection {}

/**
 * Long comment with description (rendered).
 *
 * The first sentence of the long description starts here and continues on this
 * line for a while finally concluding here at the end of this paragraph.
 *
 * The long description is ideal for more detailed explanations and
 * documentation. It can include example HTML, URLs, or any other information
 * that is deemed necessary or useful.
 *
 * 1. Set height.
 * 2. Disable spasmodic transition in Opera 12 (+ older).
 *
 * TODO: This is a todo statement that describes an atomic task to be completed
 *   at a later date. It wraps after 80 characters and following lines are
 *   indented by 2 spaces.
 */

.selector {
    height: 0; /* 1 */
    -o-transition: none; /* 2 */
}

// Multiline comment (not rendered)
// @link https://github.com/mvcss/mvcss/blob/master/core/_helpers.sass
@function em($target, $context: $base-font-size) {
    ..
}

// Basic comment (not rendered).
$variable: value;


// =============================================================================
// Mixins
// =============================================================================

/**
 * Sets element maximum dimensions.
 *
 * @param {Number} $width  (100%)
 * @param {Number} $height (100%)
 */

@mixin max($width: 100%,$height: 100%) {
    ..
}

/**
 * Sets element minimum dimensions.
 *
 * @param {Number} $width  (0)
 * @param {Number} $height (0)
 */

@mixin min($width: 0, $height: 0) {
    ..
}

// =============================================================================
// Extends
// =============================================================================

/**
 * Truncates string with ellipsis.
 */

%truncate {
    ..
}

/**
 * Provides `microfix` for group of elements.
 *
 * @requires {Mixin} microfix
 */

%group {
    ..
}

// =============================================================================
// Functions
// =============================================================================

/**
 * Gets map of colors operations and their values to pass to transform
 *  `$b` color from `$a` color.
 *
 * @author Hugo Giraudel
 * @link http://goo.gl/9BRthi
 *
 * @param  {Color} $a
 * @param  {Color} $b
 * @return {Map} - Map of color operations to do in order to
 *  transform `$b` from `$a`
 */

@function color-diff-get($a, $b) {
    ..
}

/**
 * Converts `px` to `em` units.
 *
 * @param  {Number} $target
 * @param  {Number} $context - Context `font-size`
 * @return {String}
 *
 * @example scss
 *  .selector {
 *      font-size: em(24);
 *  }
 */

@function em($target, $context: $base-font-size) {
    ..
}

Table of contents


Format

The chosen code format must ensure that code is:

  • easy to read,
  • easy to comment,
  • minimizes the chance of accidentally introducing errors
  • and results in useful diffs and blames.

Format rules

  • Use one discrete selector per line in multi-selector rulesets.
  • Include a single space before the opening brace of a ruleset.
  • Include one declaration per line in a declaration block (and follow Declaration order).
  • Use one level of indentation for each declaration.
  • Include a single space after the colon of a declaration.
  • Place closing braces of declaration blocks on a new line.
  • Place the closing brace of a ruleset in the same column as the first character of the ruleset.
  • Use __lowercase and shorthand hex value__s;
    e.g. #aaa.
  • Use hex color codes #000 unless using rgba().
  • Use double quotes;
    e.g. content: "", background-image: url("foo.svg").
  • Quote attribute values in selectors;
    e.g. input[type="checkbox"].
  • Include a semi-colon at the end of the last declaration in a declaration block.
  • Avoid unnecessary shorthand declarations.
  • Last pair of a list or map should have a trailing comma if multilines.
  • Do not use vendor prefixes if not necessary;
    autoprefixer does the heavy lifting for you.
  • Do not use standalone browser hacks - use them as @mixin(s).
// Bad

// Set button background.
$button-background: (
    disable:    #d8ddf0,  // disabled
    initial:    $gray--periwinkle
);

.selector-a, .selector-b{
    zoom: 1; color: #FFFFFF;
    padding: 0 0 10px 0px;
    border: solid 1px #0f0;

    @include foo;

    .selector-c{background: red; margin: 5px 0px}

    @extend foo;

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

// Good

// Set button background.
$button-background: (
    disable:    #d8ddf0,  // disabled
    initial:    $gray--periwinkle,
);

.selector-a,
.selector-b {
    @extend foo;
    @include foo;

    $local-variable: 10;

    background-image: url("image.png");
    border: 1px solid #0f0;
    color: #fff;
    content: "";
    padding-bottom: 10px;
    zoom: 1;

    .selector-c {
        background-color: red;
        margin: 5px 0;
    }
}

Long, comma-separated property values (gradients or shadows) or @mixin parameters can be arranged across multiple lines in an effort to improve readability and produce more useful diffs.

Aim for max 80 columns per line.

.selector {
    background-image:
        linear-gradient(#fff, #ccc),
        linear-gradient(#f3c, #4ec);
    box-shadow:
        1px 1px 1px #000,
        2px 2px 1px 1px #ccc inset;
}

@mixin foo(
    $family,
    $file,
    $style: normal,
    $weight: normal,
    $cache-buster: ""
) {
    @font-face {
        ...
    }
}

Exceptions and deviations

Large blocks of single declarations can use a slightly different, single-line format.
In this case, a space should be included after the opening brace and before the closing brace.

.selector-1 { width: 10%; }
.selector-2 { width: 20%; }
.selector-3 { width: 30%; }

Declaration order

  • Use alphabetical ordering (simplicity and ease-of-maintenance).
  • Place @extend statements on the first lines of a declaration block.
  • Group @include statements at the top of a declaration block (right after @extend statements).
  • Place local variables at the top of declaration block (right before @extend/@include statements).
  • Place @media queries at the bottom of declaration block.

Table of contents


Units

  • Define font-size in pixels and use relevant mixins where needed.
  • Use unitless line-height.
  • Avoid specifying units for zero values;
    e.g. margin: 0; instead of margin: 0px;.
  • Do not omit leading zeros for units;
    e.g. margin: 0.5em; instead of margin: .5em;.

Table of contents


Specificity

Follow these rules to avoid completely non-reusable code due to the extreme specificity of selectors.

Inception Rule

Follow the updated The Inception Rule:

Don’t go more than three levels deep!

In other words, do not overuse Sass Nested rules feature, aim for three levels and nest rules as few as possible.

Classes vs. IDs

Do not use IDs.
There's no benefit to prefer ids to classes at all.

/* Bad */
#component {}

/* Bullshit */
#component-a {
    #component-b {}
}

/* Good */
.component {}

Semantic selectors

If possible, use only selectors that includes semantics. A span or div holds none. A heading has some. A class has plenty.

Avoid element specific selectors.

/* Bad */
span.module {}

/* Good */
.module {}

Rule !important

Try to avoid the rule and use it carefully.

Table of contents


Naming conventions

Prefix layer/component with its name abbreviation (3 chars at least).
That naming convetion makes it easier for developer to localize the component (besides sourcemaps).

CSS Classes

Naming is fully based on BEM methodology.

  • Use lowercase hyphen/lodash-separated semantic names.
/**
 * Component ComponentName.
 *
 * @requires {function}    function
 * @requires {mixin}       mixin
 * @requires {placeholder} %placeholder
 * @requires {variable}    $variable
 * @requires component
 */

// =============================================================================
// ComponentName
// =============================================================================

// .component {}

/**
 * Modifiers.
 */

// .component--modifier {}

// .component {
//     &.--modifier {}
// }

/**
 * States.
 */

// .is-component-state {}

// .component {
//     &.is-state {}
// }

/**
 * Context.
 */

// .has-component {}

/**
 * Animations.
 */

// @keyframes component-animation {}

// =============================================================================
// Subcomponents
// =============================================================================

// SubcomponentName
// =============================================================================

// .component__subcomponent {}

Sass Variables and Helpers

  • Use lowercase hyphen-separated semantic names.
  • Two hyphens are allowed for naming module modifiers variables (CSS classes naming convetions analogy).
  • Use full component/layer names as an variable prefix (unlike CSS class names).
  • Use Sass maps for setting component states.
// =============================================================================
// Variables
// =============================================================================

// Set component property.
$component-property: value;

// Set component property.
$component-property: (
    active:     ,   // pressed
    disable:    ,   // disabled
    focus:      ,   // focused
    hover:      ,   // hovered
    initial:    ,
);

// Set component subcomponent property.
$component-subcomponent-property: value;

// Set component modifier property.
$component--modifier-property: value;

Table of contents


Clone this wiki locally