“Every line of code should appear to be written by a single person, no matter the number of contributors.” —@mdo
- Avoid using HTML tags in CSS selectors
- E.g. Prefer
.o-modal {}
overdiv.o-modal {}
- Always prefer using a class over HTML tags (with some exceptions like CSS resets)
- E.g. Prefer
- Don't use ids in selectors
#header
is overly specific compared to, for example.header
and is much harder to override- Read more about the headaches associated with IDs in CSS here.
- Don’t nest more than 3 levels deep
- Nesting selectors increases specificity, meaning that overriding any CSS set therein needs to be targeted with an even more specific selector. This quickly becomes a significant maintenance issue.
- Avoid using nesting for anything other than pseudo selectors and state selectors.
- E.g. nesting
:hover
,:focus
,::before
, etc. is OK, but nesting selectors inside selectors should be avoided.
- E.g. nesting
- Don't
!important
- Ever.
- If you must, leave a comment, and prioritise resolving specificity issues before resorting to
!important
. !important
greatly increases the power of a CSS declaration, making it extremely tough to override in the future. It’s only possible to override with another!important
declaration later in the cascade.
- Don’t use
margin-top
.- Vertical margins collapse. Always prefer
padding-top
ormargin-bottom
on preceding elements
- Vertical margins collapse. Always prefer
- Avoid shorthand properties (unless you really need them)
- It can be tempting to use, for instance,
background: #fff
instead ofbackground-color: #fff
, but doing so overrides other values encapsulated by the shorthand property. (In this case,background-image
and its associative properties are set to “none.” - This applies to all properties with a shorthand: border, margin, padding, font, etc.
- It can be tempting to use, for instance,
- Four spaces for indenting code
- Put spaces after
:
in property declarations- E.g.
color: red;
instead ofcolor:red;
- E.g.
- Put spaces before
{
in rule declarations- E.g.
.o-modal {
instead of.o-modal{
- E.g.
- Write your CSS one line per property
- Add a line break after
}
closing rule declarations - When grouping selectors, keep individual selectors on a single line
- Place closing braces
}
on a new line - Add a new line at the end of .scss files
- Trim excess whitespace
- All selectors are lower case, hyphen separated aka “spinal case” eg.
.my-class-name
- Always prefer Sass’s double-slash
//
commenting, even for block comments - Avoid specifying units for zero values, e.g.
margin: 0;
instead ofmargin: 0px;
- Always add a semicolon to the end of a property/value declaration
- Use leading zeros for decimal values
opacity: 0.4;
instead ofopacity: .4;
- Put spaces before and after child selector
div > span
instead ofdiv>span
- Imports
- Variables
- Base Styles
- Experiment Styles
Example:
//------------------------------
// Modal
//------------------------------
@import "../constants";
@import "../helpers";
$DBmodal-namespace: "c-modal" !default;
$DBmodal-padding: 32px;
$DBmodal-background: #fff !default;
$DBmodal-background-alt: color(gray, x-light) !default;
.o-modal { ... }
// Many lines later...
// EXPERIMENT: experiment-rule-name
.o-modal--experiment { ... }
// END EXPERIMENT: experiment-rule-name
- Define all variables at the top of the file after the imports
- Namespace local variables with the filename (SASS has no doc level scope)
- eg
business_contact.scss
→$business_contact_font_size: 14px;
- eg
- Local variables should be
$snake_lowercase
- Global constants should be
$SNAKE_ALL_CAPS
- Use the defined color constants via the color function
- Lowercase all hex values
#fffff
- Limit alpha values to a maximum of two decimal places. Always use a leading zero.
Example:
// Bad
.c-link {
color: #007ee5;
border-color: #FFF;
background-color: rgba(#FFF, .0625);
}
// Good
.c-link {
color: color(blue);
border-color: #ffffff;
background-color: rgba(#ffffff, 0.1);
}
Wrap experiment styles with comments:
// EXPERIMENT: experiment-rule-name
.stuff { ... }
// END EXPERIMENT: experiment-rule-name
Properties and nested declarations should appear in the following order, with line breaks between groups:
- Any
@
rules - Layout and box-model properties
- margin, padding, box-sizing, overflow, position, display, width/height, etc.
- Typographic properties
- E.g. font-, line-height, letter-spacing, text-, etc.
- Stylistic properties
- color, background-*, animation, border, etc.
- UI properties
- appearance, cursor, user-select, pointer-events, etc.
- Pseudo-elements
- ::after, ::before, ::selection, etc.
- Pseudo-selectors
- :hover, :focus, :active, etc.
- Modifier classes
- Nested elements
Here’s a comprehensive example:
.c-btn {
@extend %link--plain;
display: inline-block;
padding: 6px 12px;
text-align: center;
font-weight: 600;
background-color: color(blue);
border-radius: 3px;
color: white;
&::before {
content: '';
}
&:focus, &:hover {
box-shadow: 0 0 0 1px color(blue, .3);
}
&--big {
padding: 12px 24px;
}
> .c-icon {
margin-right: 6px;
}
}
- As a general rule of thumb, avoid nesting selectors more than 3 levels deep
- Prefer using nesting as a convenience to extend the parent selector over targeting nested elements. For example:
.block { padding: 24px; &--mini { padding: 12px; } }
Nesting can be really easily avoided by smart class naming (with the help of BEM) and avoiding bare tag selectors.
Block: Unique, meaningful names for a logical unit of style. Avoid excessive shorthand.
- Good:
.alert-box
or.recents-intro
or.button
- Bad:
.feature
or.content
or.btn
Element: styles that only apply to children of a block. Elements can also be blocks themselves. Class name is a concatenation of the block name, two underscores and the element name. Examples:
.alert-box__close
.expanding-section__section
Modifier: override or extend the base styles of a block or element with modifier styles. Class name is a concatenation of the block (or element) name, two hyphens and the modifier name. Examples:
.alert-box--success
.expanding-section--expanded
Don't @extend
block modifiers with the block base.
- Good:
<div class="my-block my-block--modifier">
- Bad:
<div class="my-block--modifier">
Don't create elements inside elements. If you find yourself needing this, consider converting your element into a block.
- Bad:
.alert-box__close__button
Choose your modifiers wisely. These two rules have very different meaning:
.block--modifier .block__element { color: red; }
.block__element--modifier { color: red; }
- Try to use BEM-based naming for your class selectors
- When using modifier classes, always require the base/unmodified class is present
- Use Sass’s nesting to manage BEM selectors like so:
.block { &--modifier { // compiles to .block--modifier text-align: center; } &__element { // compiles to .block__element color: red; &--modifier { // compiles to .block__element--modifier color: blue; } } }
There are a few reserved namespaces for classes to provide common and globally-available abstractions.
.o-
for CSS objects. Objects are usually common design patterns (like the Flag object). Modifying these classes could have severe knock-on effects..c-
for CSS components. Components are designed pieces of UI—think buttons, inputs, modals, and banners..u-
for helpers and utilities. Utility classes are usually single-purpose and have high priority. Things like floating elements, trimming margins, etc..is-, .has-
for stateful classes, a la SMACSS. Use these classes for temporary, optional, or short-lived states and styles.._
for hacks. Classes with a hack namespace should be used when you need to force a style with!important
or increasing specificity, should be temporary, and should not be bound onto..t-
for theme classes. Pages with unique styles or overrides for any objects or components should make use of theme classes.
You should always try to spot common code—padding, font sizes, layout patterns—and abstract them to reusable, namespaced classes that can be chained to elements and have a single responsibility. Doing so helps prevent overrides and duplicated rules, and encourages a separation of concerns.
// Bad code
// HTML:
// <div class="modal compact">...</div>
.modal {
padding: 32px;
background-color: color(gray, x-light);
&.compact {
padding: 24px;
}
}
// Good code
// HTML:
// <div class="c-modal u-l-island">...</div>
// <div class="c-modal u-l-isle">...</div>
// components/_modal.scss
.c-modal {
background-color: color(gray, x-light);
}
// helpers/_layout.scss
.u-l-island {
padding: 32px;
}
.u-l-isle {
padding: 24px;
}
Media queries should be within the CSS selector as per SMACSS
.selector {
float: left;
@media only screen and (max-width: 767px) {
float: none;
}
}
Create variables for frequently used breakpoints
$SCREEN_SM_MAX: "max-width: 767px";
.selector {
float: left;
@media only screen and ($SCREEN_SM_MAX) {
float: none;
}
}