How we go about CSS/Scss. It’s not perfect, but a good and reasonable starting point.
Note: All code examples are written using Scss single line comments.
Overview of terms used in this document. For a more detailed explaination learn more here.
Ruleset also called Rule, refers to the selector group and associated declaration block.
// Rule
.selector {
property: value;
}
The Selector or Selector Group, defines the elements to which the associated declaration block belongs to. Multiple Selectors are separated by commas.
// Selector
.selector1,
.selector2 {
// [...]
}
Declaration refers to the set of property/values within a Declaration Block.
// Declaration Block
/* Some Selector */ {
// Single Declaration
property: value;
}
TL:DR;
{ in rule declaration} need to be on their own lineUse soft tabs (4 spaces) for indentation
It is preferred to use soft tabs vs. hard tabs. Soft tabs are slightly better practice due to improved readability in teams that use different text editors. This mainly affects larger teams, due to different editors giving different spacing for hard tabs.
// Bad
.some-class {
••color: red;
}
// Good
.some-class {
••••color: green;
}
Never use ID’s for styling
Using an ID to select styles is generally considered an anti-pattern. ID’s introduce unneeded specificity. They are also not reusable. Generally, if you need an ID to style something you are doing something wrong.
// Bad
#lol {
color: red;
}
// Good
.lol {
color: green;
}
When using multiple selectors for a rule set give each selector it’s own line
This is for readability and consistency– which often go hand-in-hand.
// Bad
.class-one, .class-two, .class-three {
color: red;
}
// Good
.class-one,
.class-two,
.class-three {
color: green;
}
Put a space before the opening brace { in rule declaration
This is for readability and consistency– which often go hand-in-hand.
// Bad
.some-class{
color: red;
}
// Good
.some-class {
color: green;
}
Closing braces } need to be on their own line
This is for readability and consistency– which often go hand-in-hand.
// Bad
.some-class {
color: red;}
// Good
.some-class {
color: green;
}
Place blank lines between each rule set
This is for readability and consistency– which often go hand-in-hand.
// Bad
.some-class {
color: yellow;
}
.some-class-that-is-way-to-close {
color: red;
}
// Good
.some-class {
color: yellow;
}
.a-better-spaced-class {
color: green;
}
Comments should be Scss single line comments. Each comment should be on it’s own line and located above the styles being commented on.
// Scss single line comments is good
// Useful even when
// splitting comments across multiple lines
/* Avoid CSS comment blocks */
It is helpful to avoid binding your classes to both CSS and JS. Sharing classes between both mediums can bring confusion and lead to future difficulties refactoring. Developers will need to look in both places before removing class names, and possibly may leaving dead classes for fear of breaking things.
It is recommended to prefix JS specific class hooks with js-. Do not style JS hook classes.
<section class="ComponentName js-hookName">
...
</section>
Our preferred naming convention is a flavor of the popular BEM (Block, Element, Modifier) naming scheme. Utility class/libraries and other composable classes do not need to follow this convention.
Syntax: <ComponentName>[-descendentName][--modifierName]
Learn more about BEM:
Base “blocks” are named using PascalCase. Nothing else in HTML/CSS uses or use this naming style. Following this syntax improves readability and encourages better style encapsulation.
.ComponentName {
// [...]
}
<section class="ComponentName">
...
</section>
Component modifiers are classes that modify the styles/presentation of the base component. Modifiers should be written in camelCase and be separated from the base component by two hyphens. Modifiers build off of the base component, and should be used in addition to the base component.
.ComponentName {
// [...]
}
.ComponentName--modifierName {
// [...]
}
<section class="ComponentName ComponentName--modifierName">
...
</section>
The component descendent is a class attached to the descendent of a node/element. Components should be written in camelCase and are seperated from base component by one hyphen.
.ComponentName {
// [...]
}
.ComponentName-descendent {
// [...]
}
<section class="ComponentName">
<div class="ComponentName-descendent">
...
</div>
<div class="ComponentName-someOtherDescendent">
...
</div>
</section>
Make use of state classes to communicate changes to the component’s state. State classes must be written in camelCase. Never apply styles directly to state classes. This is so common state classes can be defined for multiple components without fighting conflicting styles.
.ComponentName.is-nameOfState {
// [...]
}
<section class="ComponentName is-nameOfState">
...
</section>
We use Scss (.scss) syntax. Never use the orignal Sass syntax (.sass).
It is important to use consistant ordering to improve readability.
Place @includes at the end of the declaration block. We find this makes it easier to read the ruleset.
.ComponentName {
color: red;
background: white;
@include transition(color 250ms ease);
}
Nested rules, when used, should be placed last in the parent ruleset. Nothing should come after them.
Do not nest rules more than three levels deep.
Nesting rules adds complexity due to reduced readability and increased specificty. Our .ComponentName BEM flavored syntax is designed to reduce specificty related complexity while preventing naming collision.
Long nested rulesets are tightly coupled with HTML making them fragile and not reusable.
// Bad
.ComponentName {
.ComponentName-descendentName {
p {
span {
// [...]
}
}
}
}
// Good
.ComponentName {
span {
// [...]
}
}
// Or also good
.ComponentName-descendentName {
span {
// [...]
}
}
Various parts of both the structure and the language have been inspired by the following: