Back to main page

Table of Contents


STYLES (CSS/SCSS)

CSS

USE CSS RESET OR NORMALIZE CSS

NEVER USE INLINE STYLES

When creating the markup, do not use inline styling because it would be very hard to override them when needed and any desired changes to styles have to be made in the HTML. Consequently, these styles cannot be reused, and the consistency of the styles will likely suffer.

Instead of these styles we can use:

MODULARIZE STYLES FOR REUSE

CSS is built to allow styles to be reused, specifically with the use of classes. For this reason, styles assigned to a class should be modular and available to share across elements as necessary.

CLASS NAMES

It is also useful to apply many of those rules when defining Sass/Less variable names.

STATE CLASSES

Use the .is-* prefix for state classes that are shared between CSS/SCSS and JavaScript to denote a temporary styling application.

Example:

<div class="accordion-tab is-active" data-accordion="true">
    ...
</div>

USE MULTIPLE STYLESHEETS, BUT BE AWARE OF THEM EXPANDING BEYOND CONTROL

Depending on the complexity of the design and the size of the website, sometimes it is easier to make smaller, multiple stylesheets (or partials in Sass/SCSS/Less) instead of a giant one. Having multiple files/partials, improve the maintainability developers can easily maintain

Note: if we are working with a JavaScript framework, this is really helpful because (usually) it can load only the styles that are needed for the components used in the current view, instead of loading one giant CSS file that contains styles that are used elsewhere in the website/application).

ORGANIZE CSS WITH COMMENTS

Let’s keep our styles organized in logical groups and provide a comment noting what the following styles pertain to. Learn more about comments in the General section of this guide.

NEVER USE LARGE FIXED WIDTH ELEMENTS

Adjust the content to fit within the width of the viewport. For example, if an image is displayed at a width wider than the viewport it can cause the viewport to scroll horizontally: use instead width: 100% that keeps the image at the maximum size of the parent.

NEVER LET CONTENT RELY ON A PARTICULAR VIEWPORT WIDTH

Since screen dimensions and width in CSS pixels vary widely between devices, content should not rely on a particular viewport width to render well. For example:

/* Don't do this */
body {
    width: 1024px;
}

/* Do this instead */
body {
    max-width: 1024px;
}

This means also that we should not rely on the element’s fixed sizes to stack other elements alongside the first one: whenever possible use percentages for widths and heights or use Flexbox.

WHITESPACING AND FORMATTING

PROPER SPACING BETWEEN PROPERTIES

/* Don't do this */
.selector{display:none;background:rgba(2,0,36,.5);color:#000} 

/* Do this */
.selector { display: none; background: rgba(2, 0, 36, .5); color: #000; } 

/* This is even better - for the sake of readability */
.selector {
    display: none;
    background: rgba(2, 0, 36, .5);
    color: #000;
}

ONE SELECTOR PER LINE

/* Don't do this */
.selector-one, .selector-two, .selector-three {
    display: none;
    background: #f00;
    color: #000;
}

/* Do this instead */
.selector-one,
.selector-two,
.selector-three {
    display: none;
    background: #f00;
    color: #000;
}

BLANK LINE BETWEEN RULESETS

/* Don't do this */
.selector-one {
    display: none;
    background: #f00;
    color: #000;
}
.selector-two,
.selector-three {
    display: block;
    background: #0f0;
    color: #00f;
}

/* Do this instead */
.selector-one {
    display: none;
    background: #f00;
    color: #000;
}

.selector-two,
.selector-three {
    display: block;
    background: #0f0;
    color: #00f;
}
/* Don't do this */
.selector {
    display: none;
    background: #f00;
    color: #000;
    &__child {
        display: block;
        background: #0f0;
        color: #00f;
    }
}

/* Do this instead */
.selector {
    display: none;
    background: #f00;
    color: #000;

    &__child {
        display: block;
        background: #0f0;
        color: #00f;
    }
}

SAME LINE OPENING BRACES

/* Don't do this */
.selector
{
    display: none;
    background: #f00;
    color: #000;
}

/* Do this instead */
.selector {
    display: none;
    background: #f00;
    color: #000;
}

SAME COLUMN CLOSING BRACES AS THE FIRST CHARACTER OF THE RULESET

/* Don't do this */
.selector {
    display: none;
    background: #f00;
    color: #000; }

/* Do this instead */
.selector {
    display: none;
    background: #f00;
    color: #000;
}

INDENTING CHILD ELEMENTS

Use 4 spaces on each indentation.

.selector {
    display: none;
    background: #f00;
    color: #000;

    &__child {
        text-decoration: none;
    }

    span {
        font-weight: bold;
    }
}

END ALL DECLARATIONS WITH A SEMICOLON

The last declarations semicolon is optional, but your code is more error prone without it.

/* Don't do this */
.selector {
    color: red
}

/* Do this instead */
.selector {
    color: red;
}

USE DOUBLE QUOTES IN STYLE FILES

/* Don't do this */
.selector {
    content: '';
}

/* Do this instead */
.selector {
    content: "";
}

DOUBLE QUOTE ATTRIBUTE VALUES

/* Don't do this */
input[type=checkbox] {
    color: red;
}

/* Do this instead */
input[type="checkbox"] {
    color: red;
}

Further reading about the reason behind this choice.

AVOID UNITS ON ZERO VALUES

One way to easily cut down on the amount of CSS we write is to remove the unit from any zero value: a zero will always be a zero.

/* Don't do this */
.selector { 
    margin: 0px;
    padding: 0rem;
}

/* Do this instead */
.selector { 
    margin: 0;
    padding: 0;
}

GROUPING VENDOR PREFIXES

DO NOT use all the major prefixes on every single CSS3 property.

It appears that many generic mixins are just putting everything with the prefixes: something like -o-border-radius has never existed and never needs to go into your CSS. Consult CanIUse if you have doubts about a property.

If you have to use them, insert them before the standard property.

.selector-1 {
    -webkit-transition: all 4s ease; /* Android, Chrome, iOS, Edge */
    -moz-transition: all 4s ease; /* FireFox */
    -ms-transition: all 4s ease; /* Internet Explorer */
    -o-transition: all 4s ease; /* Opera */
    transition: all 4s ease; /* Modern browsers */
}

.selector-2 {
    background-image: -webkit-linear-gradient(#a1d3b0, #f6f1d3);
    background-image: -moz-linear-gradient(#a1d3b0, #f6f1d3);
    background-image: -ms-linear-gradient(#a1d3b0, #f6f1d3);
    background-image: -o-linear-gradient(#a1d3b0, #f6f1d3);
    background-image: linear-gradient(#a1d3b0, #f6f1d3);
    -ms-filter: "progid:DXImageTransform.Microsoft.Gradient(startColorStr='#a1d3b0', endColorStr='#f6f1d3', GradientType=0)"; /* linear gradient for IE8+ */
    filter: progid:DXImageTransform.Microsoft.Gradient(startColorStr='#a1d3b0', endColorStr='#f6f1d3', GradientType=0); /* linear gradient for IE7- */
}

PROPERTIES ORDER

For the sake of readability, I structure all the properties in alphabetical order with the exception of the ones that are ruling the position of the element (float, position, top, left, right, bottom) and the visibility (display) at the top of the declaration.

I also put the ones that are ruling the dimensions (max-height, max-width, height and width) at the bottom where width rule should be (considering alphabetical order).

Example:

.selector { 
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: block;
    background-color: #ff0000;
    border: 1px solid #00ff00;
    color: #0000ff;
    font-size: 1rem;
    line-height: 1;
    margin: 0 auto;
    padding: .5rem 1rem;
    max-width: 10rem;
    height: auto;
    z-index: 10;
}

Positioning rules come first because they can remove an element from the normal flow of the document and override box model related styles.

EXCEPTION

All extensions and inclusions that are coming from Sass features, should be placed at the top of the declarations, even before the positioning properties, like in the following example:

.selector { 
    @extend .extendedClass;
    @include transition(0.3s, ease-all)
    display: block;
    background-color: #ff0000; 
    border: 1px solid #00ff00;
    color: #0000ff;
    height: 2rem;
    width: 100%;
}

More on this further below.

LONG COMMA-SEPARATED PROPERTY VALUES

Those properties (such as collections of gradients or shadows) can be arranged across multiple lines in an effort to improve readability and produce more useful diffs (when checked in).

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

KEEP THE NATURAL FLOW

Do not change the default behaviour of an element whenever possible.

Keep elements in the natural document flow as much as possible.

/* Don't do this */
div {
    display: block; /* it is redundant */
    color: red
}

/* Do this instead */
div {
    color: red;
}

Similarly, do not bring an element off the flow if you can avoid it.

/* Don't do this */
.selector {
    position: absolute;
    right: 0;
    width: 100px;
}

/* Do this instead */
.selector {
    margin-left: auto;
    width: 100px;
}

TYPOGRAPHY

FONT SIZE

Avoid setting a default font-size on the html or body selectors. Browsers have a default size of 16px that we can use as a baseline.

We can control font-size proportion with relative sizing units rem or em.

If you need to, use a percentage unit on the :root or html selector’s font-size property.

For example, in case of 20px default project’s font size, use:

html {
    font-size: 125%; // (125/100) * 16px = 20px
}

the project’s root font size would then be 20px, therefore, 1.5rem would be 30px.

PIXELS vs EMs vs. REMs FOR TYPOGRAPHY

Use rems or ems over pxs for font sizes: as recommended in the previous point, these units are scalable and therefore, they offer users the control over the size of the text. More about this here.

Additionally, a unitless line-height is preferred because it does not inherit a percentage value of its parent element, but instead is based on a multiplier of the font-size.

/* Don't do this */
.selector { 
    font-size: 16px;
    line-height: 24px;
}

/* Do this instead */
.selector { 
    font-size: 1rem;
    line-height: 1.5;
}

Read more about when and how we should use ems or rems here.

FONT ADJUSTMENT

To help prevent adjustments of font sizes after iOS device orientation changes, use text-size-adjust: 100% in the body tag so it will be inherited by its children.

body {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

More about text-size-adjust in the MDN documentation

Notice that modern Safari versions are no more using the user-scalable trick in the meta tag viewport, while in older versions this is still effective. Read more about this in this StackOverflow question

INHERITANCE

Don’t duplicate style declarations that can be inherited.

/* Don't do this */
.parent-selector {
    text-shadow: 0 1px 0 #000;
}

.child-selector {
    text-shadow: 0 1px 0 #000;
}

/* Just do this */
.parent-selector {
    text-shadow: 0 1px 0 #000;
}

More on CSS Inheritance on MDN web docs and in this StackOverflow answer that has a complete list of properties that can be inherited.

USE SHORTHAND

One feature of CSS is the ability to use shorthand properties and values. Using that allows us to quickly set and identify styles (margin, padding, border, animation, flex, etc).

/* Don't do this */
.selector {
    padding-top: 1rem;
    padding-left: 2rem;
    padding-right: 2rem;
    padding-bottom: 1rem;
}

/* Do this */
.selector {
    padding: 1rem 2rem 1rem 2rem;
}

/* This is even better */
.selector {
    padding: 1rem 2rem;
}

On the contrary, when we are only setting just one value, shorthand alternatives should not be used because it will be hard to identify immediately which CSS attribute is being applied.

/* Don't do this */
.selector {
    border: red;
    background: center;
    margin: 1rem 0 0 0;
}

/* Do this instead */
.selector {
    border-color: red;
    background-position: center;
    margin-top: 1rem;
}

More on shorthand properties on the MDN documentation.

EXCEPTIONS

There are few exceptions to that standard: those are particularly related to the font and background properties.

In both these cases, it is not always easy to read the shorthand rule and/or understand immediately what the single rule in the shorthand is related to (i.e. background-position and background-size).

Furthermore, the shorthanded property could become quite long losing readability and breaking the IDE’s 80 columns rule.

In those cases, I prefer to use the complete and full property.

/* Don't do this */
.selector {
    background: url('../images/branding/logo.png') 10rem 2rem center 100% no-repeat;
}

/* Do this instead */
.selector {
    background-image: url('../images/branding/logo.png');
    background-size: 10rem 2rem;
    background-position: center 100%;
    background-repeat: no-repeat;
}

/* Notice that `background-position` and `background-repeat` are already shorthand properties themselves */
/* Don't do this */
.selector {
    font: italic small-caps 800 1rem/1.5 "Segoe UI", Verdana, Arial, Helvetica, sans-serif;
}

/* Do this instead */
.selector {
    font-family: "Segoe UI", Verdana, Arial, Helvetica, sans-serif;
    font-size: 1rem;
    font-style: italic;
    font-variant: small-caps;
    font-weight: 800;
    line-height: 1.5;
}

NEVER EVER USE !IMPORTANT

Never ever use !important. That’s it!

There is always another way, check the specificity of the rules and eventually amend them.

Avoiding the use of this attribute is the first step to keep a pretty good level of maintainability.

Side note: the only rare case when there is the necessity to override a third party stylesheet, which we do not have access or permission to edit, is the only exception where this property can be admitted.

SELECTORS

MINIMIZE SELECTORS TIGHTLY COUPLED TO THE DOM ELEMENTS

Consider adding a class to the HTML elements you want to match, especially when your selector exceeds 3 structural pseudo-classes, descendant or sibling combinators.

/* Don't do this */
div p a {
    color: orange;
    text-decoration: none;
}

/* Do this instead */
.paragraph__link {
    color: orange;
    text-decoration: none;
}

MINIMIZE SELECTOR ACCESSES TO THE DOM

Consider using structural pseudo-classes, descendant or sibling combinators when you realize there are multiple accesses to the DOM when writing a CSS rule.

/* Don't do this */
.article .paragraph .paragraph__link { /* 3 accesses to the DOM to find the elements */
    color: orange;
    text-decoration: none;
}

/* Do this instead */
.article > .paragraph > .paragraph__link { /* 1 access to the DOM to find the elements */
    color: orange;
    text-decoration: none;
}

POSITIONING

COLOURS

MEDIA QUERIES

RESPONSIVE LAYOUTS

Use CSS media queries to apply different styling for small and large screens.

APPROACH

Use mobile-first approach.

PLACING MEDIA QUERIES

Place media queries as close to their relevant rulesets, whenever possible. Do not bundle them all in a separate stylesheet or at the end of the file. Doing so only makes it easier for developers to miss them in the future.

SASS/SCSS SPECIFIC STANDARDS

EXTENSIONS AND INCLUSIONS AT THE TOP OF THE RULESET

All extensions and inclusions should be placed at the top of the declarations because they may have rule(s) that can be specifically overwritten by the ruleset that is extending or including them.

.selector { 
    @extend .extendedClass;
    @include box-sizing(border-box);
    @include clearfix();
    @include transition(0.3s, ease-all)
    display: block;
    background-color: #ff0000;
    border: 1px solid #00ff00;
    color: #0000ff;
    height: 2rem;
    width: 100%;
}

OPERATORS

Wrap all math operations in parentheses with a single space between values, variables, and operators.

/* Don't do this */
.selector {
    margin: 10px 0 $variable*2 10px;
}

/* Do this instead */
.selector {
    margin: 10px 0 ($variable * 2) 10px;
}