|
CSS + Sass
|
|
# Principles of writing consistent, idiomatic CSS
|
|
==========
|
|
|
|
|
|
|
|
All of the following standards and practices on this page describe both CSS and Sass, unless otherwise noted.
|
|
The following document outlines a reasonable style guide for CSS development.
|
|
|
|
These guidelines strongly encourage the use of existing, common, sensible
|
|
|
|
patterns. They should be adapted as needed to create your own style guide.
|
|
|
|
|
|
|
|
This is a living document and new ideas are always welcome. Please
|
|
|
|
contribute.
|
|
|
|
|
|
|
|
|
|
|
|
## Table of contents
|
|
|
|
|
|
Structure
|
|
1. [General principles](#general-principles)
|
|
---------
|
|
2. [Whitespace](#whitespace)
|
|
|
|
3. [Comments](#comments)
|
|
|
|
4. [Format](#format)
|
|
|
|
5. [Practical example](#example)
|
|
|
|
|
|
- Use 4-space indents, not tabs
|
|
[Acknowledgements](#acknowledgements)
|
|
- Add four blank lines between sections and one blank line between blocks in a section
|
|
|
|
- Each selector should be on its own line, ending in either a comma or an opening curly brace
|
|
|
|
- Property-value pairs can be on a single line, if there is only one pair for the selector, otherwise they should be on their own line
|
|
|
|
- Optionally, sets of property-value pairs can align vertically on the `:` chracter
|
|
|
|
- The closing brace should be left-aligned, using the same level of indentation as the opening selector
|
|
|
|
|
|
|
|
|
|
[License](#license)
|
|
|
|
|
|
#### Wrong
|
|
|
|
|
|
|
|
- Multiple selectors are on the same line
|
|
<a name="general-principles"></a>
|
|
- The closing brace isn't left-aligned with the opening selector
|
|
## 1. General principles
|
|
- `.selector-4` has 2 property-value pairs on a single line. Only a single pair is allowed for shorthand single-line declarations.
|
|
|
|
|
|
|
|
```
|
|
> "Part of being a good steward to a successful project is realizing that
|
|
.selector-1, .selector-2, .selector-3 {
|
|
> writing code for yourself is a Bad Idea™. If thousands of people are using
|
|
background: #fff;
|
|
> your code, then write your code for maximum clarity, not your personal
|
|
color: #000;
|
|
> preference of how to get clever within the spec." - Idan Gazit
|
|
}
|
|
|
|
|
|
|
|
.selector-4 { background: #f00; color: #000; }
|
|
* Don't try to prematurely optimize your code; keep it readable and
|
|
```
|
|
understandable.
|
|
|
|
* All code in any code-base should look like a single person typed it, even
|
|
|
|
when many people are contributing to it.
|
|
|
|
* Strictly enforce the agreed-upon style.
|
|
|
|
* If in doubt when deciding upon a style use existing, common patterns.
|
|
|
|
|
|
|
|
|
|
|
|
<a name="whitespace"></a>
|
|
|
|
## 2. Whitespace
|
|
|
|
|
|
|
|
Only one style should exist across the entire source of your code-base. Always
|
|
|
|
be consistent in your use of whitespace. Use whitespace to improve
|
|
|
|
readability.
|
|
|
|
|
|
|
|
* _Never_ mix spaces and tabs for indentation.
|
|
|
|
* Choose between soft indents (spaces) or real tabs. Stick to your choice
|
|
|
|
without fail. (Preference: spaces)
|
|
|
|
* If using spaces, choose the number of characters used per indentation level.
|
|
|
|
(Preference: 4 spaces)
|
|
|
|
|
|
|
|
Tip: configure your editor to "show invisibles" or to automatically remove
|
|
|
|
end-of-line whitespace.
|
|
|
|
|
|
|
|
Tip: use an [EditorConfig](http://editorconfig.org/) file (or equivalent) to
|
|
|
|
help maintain the basic whitespace conventions that have been agreed for your
|
|
|
|
code-base.
|
|
|
|
|
|
|
|
|
|
|
|
<a name="comments"></a>
|
|
|
|
## 3. 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.
|
|
|
|
|
|
|
|
Tip: configure your editor to provide you with shortcuts to output agreed-upon
|
|
|
|
comment patterns.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
```css
|
|
|
|
/* ==========================================================================
|
|
|
|
Section comment block
|
|
|
|
========================================================================== */
|
|
|
|
|
|
#### Good
|
|
/* Sub-section comment block
|
|
|
|
========================================================================== */
|
|
|
|
|
|
- There are multiple property-value pairs, so aligning the colon characters could help readability.
|
|
/**
|
|
|
|
* Short description using Doxygen-style comment format
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @tag This is a tag named 'tag'
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Basic comment */
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<a name="format"></a>
|
|
|
|
## 4. Format
|
|
|
|
|
|
|
|
The chosen code format must ensure that code is: easy to read; easy to clearly
|
|
|
|
comment; minimizes the chance of accidentally introducing errors; and results
|
|
|
|
in useful diffs and blames.
|
|
|
|
|
|
|
|
* 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.
|
|
|
|
* Use one level of indentation for each declaration.
|
|
|
|
* Include a single space after the colon of a declaration.
|
|
|
|
* Use lowercase and shorthand hex values, e.g., `#aaa`.
|
|
|
|
* Use single or double quotes consistently. Preference is for double quotes,
|
|
|
|
e.g., `content: ""`.
|
|
|
|
* Quote attribute values in selectors, e.g., `input[type="checkbox"]`.
|
|
|
|
* _Where allowed_, avoid specifying units for zero-values, e.g., `margin: 0`.
|
|
|
|
* Include a space after each comma in comma-separated property or function
|
|
|
|
values.
|
|
|
|
* Include a semi-colon at the end of the last declaration in a declaration
|
|
|
|
block.
|
|
|
|
* Place the closing brace of a ruleset in the same column as the first
|
|
|
|
character of the ruleset.
|
|
|
|
* Separate each ruleset by a blank line.
|
|
|
|
|
|
|
|
```css
|
|
.selector-1,
|
|
.selector-1,
|
|
.selector-2,
|
|
.selector-2,
|
|
.selector-3 {
|
|
.selector-3[type="text"] {
|
|
|
|
-webkit-box-sizing: border-box;
|
|
|
|
-moz-box-sizing: border-box;
|
|
|
|
box-sizing: border-box;
|
|
|
|
display: block;
|
|
|
|
font-family: helvetica, arial, sans-serif;
|
|
|
|
color: #333;
|
|
background: #fff;
|
|
background: #fff;
|
|
color: #000;
|
|
background: linear-gradient(#fff, rgba(0, 0, 0, 0.8));
|
|
|
|
}
|
|
|
|
|
|
|
|
.selector-a,
|
|
|
|
.selector-b {
|
|
|
|
padding: 10px;
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
#### Best
|
|
#### Declaration order
|
|
|
|
|
|
|
|
If declarations are to be consistently ordered, it should be in accordance with
|
|
|
|
a single, simple principle.
|
|
|
|
|
|
|
|
Smaller teams may prefer to cluster related properties (e.g. positioning and
|
|
|
|
box-model) together.
|
|
|
|
|
|
|
|
```css
|
|
|
|
.selector {
|
|
|
|
/* Positioning */
|
|
|
|
position: absolute;
|
|
|
|
z-index: 10;
|
|
|
|
top: 0;
|
|
|
|
right: 0;
|
|
|
|
bottom: 0;
|
|
|
|
left: 0;
|
|
|
|
|
|
|
|
/* Display & Box Model */
|
|
|
|
display: inline-block;
|
|
|
|
overflow: hidden;
|
|
|
|
box-sizing: border-box;
|
|
|
|
width: 100px;
|
|
|
|
height: 100px;
|
|
|
|
padding: 10px;
|
|
|
|
border: 10px solid #333;
|
|
|
|
margin: 10px;
|
|
|
|
|
|
|
|
/* Other */
|
|
|
|
background: #000;
|
|
|
|
color: #fff;
|
|
|
|
font-family: sans-serif;
|
|
|
|
font-size: 16px;
|
|
|
|
text-align: right;
|
|
|
|
}
|
|
```
|
|
```
|
|
.selector-1,
|
|
|
|
.selector-2,
|
|
Larger teams may prefer the simplicity and ease-of-maintenance that comes with
|
|
.selector-3 {
|
|
alphabetical ordering.
|
|
background : #fff;
|
|
|
|
color : #000;
|
|
#### Exceptions and slight 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.
|
|
|
|
|
|
|
|
```css
|
|
|
|
.selector-1 { width: 10%; }
|
|
|
|
.selector-2 { width: 20%; }
|
|
|
|
.selector-3 { width: 30%; }
|
|
|
|
```
|
|
|
|
|
|
|
|
Long, comma-separated property values - such as collections of gradients or
|
|
|
|
shadows - can be arranged across multiple lines in an effort to improve
|
|
|
|
readability and produce more useful diffs. There are various formats that could
|
|
|
|
be used; one example is shown below.
|
|
|
|
|
|
|
|
```css
|
|
|
|
.selector {
|
|
|
|
background-image:
|
|
|
|
linear-gradient(#fff, #ccc),
|
|
|
|
linear-gradient(#f3c, #4ec);
|
|
|
|
box-shadow:
|
|
|
|
1px 1px 1px #000,
|
|
|
|
2px 2px 1px 1px #ccc inset;
|
|
}
|
|
}
|
|
``` |
|
```
|
|
\ No newline at end of file |
|
|
|
|
|
### Preprocessors: additional format considerations
|
|
|
|
|
|
|
|
Different CSS preprocessors have different features, functionality, and syntax.
|
|
|
|
Your conventions should be extended to accommodate the particularities of any
|
|
|
|
preprocessor in use. The following guidelines are in reference to Sass.
|
|
|
|
|
|
|
|
* Limit nesting to 1 level deep. Reassess any nesting more than 2 levels deep.
|
|
|
|
This prevents overly-specific CSS selectors.
|
|
|
|
* Avoid large numbers of nested rules. Break them up when readability starts to
|
|
|
|
be affected. Preference to avoid nesting that spreads over more than 20
|
|
|
|
lines.
|
|
|
|
* Always place `@extend` statements on the first lines of a declaration
|
|
|
|
block.
|
|
|
|
* Where possible, group `@include` statements at the top of a declaration
|
|
|
|
block, after any `@extend` statements.
|
|
|
|
* Consider prefixing custom functions with `x-` or another namespace. This
|
|
|
|
helps to avoid any potential to confuse your function with a native CSS
|
|
|
|
function, or to clash with functions from libraries.
|
|
|
|
|
|
|
|
```scss
|
|
|
|
.selector-1 {
|
|
|
|
@extend .other-rule;
|
|
|
|
@include clearfix();
|
|
|
|
@include box-sizing(border-box);
|
|
|
|
width: x-grid-unit(1);
|
|
|
|
// other declarations
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
<a name="example"></a>
|
|
|
|
## 5. Practical example
|
|
|
|
|
|
|
|
An example of various conventions.
|
|
|
|
|
|
|
|
```css
|
|
|
|
/* ==========================================================================
|
|
|
|
Grid layout
|
|
|
|
========================================================================== */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Column layout with horizontal scroll.
|
|
|
|
*
|
|
|
|
* This creates a single row of full-height, non-wrapping columns that can
|
|
|
|
* be browsed horizontally within their parent.
|
|
|
|
*
|
|
|
|
* Example HTML:
|
|
|
|
*
|
|
|
|
* <div class="grid">
|
|
|
|
* <div class="cell cell-3"></div>
|
|
|
|
* <div class="cell cell-3"></div>
|
|
|
|
* <div class="cell cell-3"></div>
|
|
|
|
* </div>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Grid container
|
|
|
|
*
|
|
|
|
* Must only contain `.cell` children.
|
|
|
|
*
|
|
|
|
* 1. Remove inter-cell whitespace
|
|
|
|
* 2. Prevent inline-block cells wrapping
|
|
|
|
*/
|
|
|
|
|
|
|
|
.grid {
|
|
|
|
height: 100%;
|
|
|
|
font-size: 0; /* 1 */
|
|
|
|
white-space: nowrap; /* 2 */
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Grid cells
|
|
|
|
*
|
|
|
|
* No explicit width by default. Extend with `.cell-n` classes.
|
|
|
|
*
|
|
|
|
* 1. Set the inter-cell spacing
|
|
|
|
* 2. Reset white-space inherited from `.grid`
|
|
|
|
* 3. Reset font-size inherited from `.grid`
|
|
|
|
*/
|
|
|
|
|
|
|
|
.cell {
|
|
|
|
position: relative;
|
|
|
|
display: inline-block;
|
|
|
|
overflow: hidden;
|
|
|
|
box-sizing: border-box;
|
|
|
|
height: 100%;
|
|
|
|
padding: 0 10px; /* 1 */
|
|
|
|
border: 2px solid #333;
|
|
|
|
vertical-align: top;
|
|
|
|
white-space: normal; /* 2 */
|
|
|
|
font-size: 16px; /* 3 */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cell states */
|
|
|
|
|
|
|
|
.cell.is-animating {
|
|
|
|
background-color: #fffdec;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cell dimensions
|
|
|
|
========================================================================== */
|
|
|
|
|
|
|
|
.cell-1 { width: 10%; }
|
|
|
|
.cell-2 { width: 20%; }
|
|
|
|
.cell-3 { width: 30%; }
|
|
|
|
.cell-4 { width: 40%; }
|
|
|
|
.cell-5 { width: 50%; }
|
|
|
|
|
|
|
|
/* Cell modifiers
|
|
|
|
========================================================================== */
|
|
|
|
|
|
|
|
.cell--detail,
|
|
|
|
.cell--important {
|
|
|
|
border-width: 4px;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Based on a work at
|
|
|
|
[github.com/necolas/idiomatic-css](https://github.com/necolas/idiomatic-css). |
|
|
|
\ No newline at end of file |