Based on the awesome Airbnb Style Guide
A mostly reasonable approach to CSS and Sass
- Terminology - 1.1 Rule Declaration - 1.2 Selectors - 1.3 Properties
- CSS - 2.1 Formatting - 2.2 Comments
- Sass - 3.1 Syntax - 3.2 Ordering - 3.3 Mixins - 3.4 Placeholders - 3.5 Nested selectors
- RSCSS
- Conventions
A “rule declaration” is the name given to a selector (or a group of selectors) with an accompanying group of properties. Here's an example:
.listing {
font-size: 18px;
line-height: 1.2;
}
In a rule declaration, “selectors” are the bits that determine which elements in the DOM tree will be styled by the defined properties. Selectors can match HTML elements, as well as an element's class, ID, or any of its attributes. Here are some examples of selectors:
.my-element-class {
/* ... */
}
[aria-hidden] {
/* ... */
}
Finally, properties are what give the selected elements of a rule declaration their style. Properties are key-value pairs, and a rule declaration can contain one or more property declarations. Property declarations look like this:
/* some selector */ {
background: #f1f1f1;
color: #333;
}
- 2.1.1 Use soft tabs (4 spaces) for indentation. This improves readability and keeps the space uniform
// bad
.avatar{
border-radius: 50%;
}
// good
.avatar{
border-radius: 50%;
}
- 2.1.2 Use classes for all selectors. Ids are reserved for E2E testing and data arguments are for JS libraries
// bad
#panel {
/* ... */
}
[data-panel] {
/* ... */
}
// good
.panel {
/* ... */
}
- 2.1.3 Avoid using tag selectors. Tag selectors come at a small performance penalty
// bad
h3 {
/* ... */
}
// good
.subtitle {
/* ... */
}
- 2.1.4 When using multiple selectors in a rule declaration, give each selector its own line. This way its much easier to find selectors when scanning the document
// bad
.panel, .box {
/* ... */
}
// good
.panel,
.box {
/* ... */
}
- 2.1.5 Put a space before the opening brace
{
in rule declarations. In properties, put a space after, but not before, the:
character. Put closing braces}
of rule declarations on a new line. Put blank lines between rule declarations
// bad
.panel{
font-size:2px;color:white}
// good
.panel {
font-size: 2px;
color: white;
}
- 2.1.6 Only use
!important
to keep a plane from crashing.
-
2.2.1 Prefer line comments
//
to block comments. -
2.2.1 Prefer comments on their own line. Avoid end-of-line comments.
-
3.1.1 Use the
.scss
syntax, never the original.sass
syntax -
3.1.2 Order your
@extend
,@include
declarations and regular CSS lastly with a newline between the last two.
.btn-green {
@extend %btn;
@include transition(background 0.5s ease);
background: green;
font-weight: bold;
}
- 3.1.3 Nested selectors, if necessary, go last, and nothing goes after them. Add whitespace between your rule declarations and nested selectors, as well as between adjacent nested selectors. Apply 3.1.2 as above to your nested selectors.
.btn {
@extend %btn;
background: green;
font-weight: bold;
@include transition(background 0.5s ease);
.icon {
margin-right: 10px;
}
}
Mixins, defined via @mixin
and called with @include
, should be used sparingly and only when function arguments are necessary. A mixin without function arguments (i.e. @mixin hide { display: none; }
) is better accomplished using a placeholder selector (see below) in order to prevent code duplication.
Placeholders in Sass, defined via %selector
and used with @extend
, are a way of defining rule declarations that aren't automatically output in your compiled stylesheet. Instead, other selectors “inherit” from the placeholder, and the relevant selectors are copied to the point in the stylesheet where the placeholder is defined. This is best illustrated with the example below.
Placeholders are powerful but easy to abuse, especially when combined with nested selectors. As a rule of thumb, avoid creating placeholders with nested rule declarations, or calling @extend
inside nested selectors. Placeholders are great for simple inheritance, but can easily result in the accidental creation of additional selectors without paying close attention to how and where they are used.
Sass
// Unless we call `@extend %icon` these properties won't be compiled!
%icon {
font-family: "Airglyphs";
}
.icon-error {
@extend %icon;
color: red;
}
.icon-success {
@extend %icon;
color: green;
}
Compiled CSS
.icon-error,
.icon-success {
font-family: "Airglyphs";
}
.icon-error {
color: red;
}
.icon-success {
color: green;
}
Do not nest selectors more than three levels deep!
.page-container {
.content {
.profile {
// STOP!
}
}
}
When selectors become this long, you're likely writing CSS that is:
- Strongly coupled to the HTML (fragile) —OR—
- Overly specific (powerful) —OR—
- Not reusable
- 4.1.1 Name components will be named with at least two works, seperated by a dash.
.like-button {
/* ... */
}
.search-form {
/* ... */
}
- 4.2.1 Each component may have elements. They should have classes that are only one word.
.search-form {
> .field {
/* ... */
}
> .action {
/* ... */
}
}
- 4.2.2 Always prefer to use the
>
child selector whenever possible.
.article-card {
.title {
/* okay */
}
> .author {
/* better */
}
}
- 4.2.3 For elements that need two or more words, concatenate them without dashes or underscores.
.profile-box {
> .firstname {
/* ... */
}
> .lastname {
/* ... */
}
}
- 4.3.1 Variants customize a component or an element. Variants are prefixed by a dash
-
.
.search-form {
&.-prefixed {
/* ... */
}
&.-compact {
/* ... */
}
}
- 4.4.1 When a component may need to appear a certain way when nested in another component. Avoid modifying the nested component by reaching into it from the containing component. Instead, prefer to add a variant to the nested component and apply it from the containing component.
// bad
.article-header {
> .vote-box > .up {
/* ... */
}
}
// good
.vote-box {
&.-highlight > .up {
/* ... */
}
}
-
4.5.1 Components should be made in a way that they're reusable in different contexts. Avoid putting these properties in components:
- Positioning (
position
,top
,left
,right
,bottom
) - Floats (
float
,clear
) - Margins (
margin
) - Dimensions (
width
,height
)
- Positioning (
If you need to define these, try to define them in whatever context they will be in.
.article-list {
& {
@include clearfix;
}
> .article-card {
width: 33.3%;
float: left;
}
}
.article-card {
& {
/* ... */
}
> .image {
/* ... */
}
> .title {
/* ... */
}
> .category {
/* ... */
}
}
- 5.1 Every colors need to be on the
colors.scss
file. The color name should have abrand-
prefix for the brand primary colors and a tone as a suffix.
// bad
$green: green;
$green-2: green;
//good
$brand-green: green;
$brand-green-light: green;
- 5.2 For colors where the opacity changes a suffix must be added from the available list:
- xs
- s
- m
- l
- -xl
- -xxl
- -xxxl