This document describes standards for writing robust, easily maintained and high-performance HTML & CSS code.
HTML
When using HTML5 elements, always follow the [W3 Specifications][W3-HTML-Spec]. If you need to check browser support of a specification, [caniuse.com][resource-caniuse-html] is an invaulable resource.
General HTML Syntax
- In order to guarantee that code renders the same in any environment, use soft tabs with two spaces.
- Nested elements should be indented once (two spaces) for each level.
- Never use quotes on attributes that do not have multiple values, e.g.
<a href=http://apple.com/ rel=external>
. Remember, however, that you cannot have a space, e.g.,<div class=content page>
would be invalid; only<div class="content page">
would be correct. - When an attribute requires it, use double quotes and never single quotes.
- Use lowercase and dashes (not underscore or camelCase).
- Do not include trailing slash in self-closing elements.
- Closing tags are not required on certain elements in HTML5, e.g.,
<li>
instead of<li></li>
Doctype Declaration
Enforce standards mode and more consistent rendering in every browser by declaring the HTML5 doctype at the beginning of every HTML page.
<!DOCTYPE html>
Space
If an HTML document has complex markup and spacing will help a developer navigate the code easier, use one line-break to separate major blocks of code from one another.
<main>
<section>
...
</section>
<section>
...
</section>
</main>
LESS and Sass
[LESS][LESS] and [Sass][Sass] are two CSS preprocessors that add variables, nesting, functions, and mixins to your stylesheets and both are equally as powerful as the other. This document uses LESS syntax for examples, but Sass is very similiar; follow the same styleguide rules for both.
Notes:
- Always write Sass with only on the first "S" capitalized.
- LESS is written in uppercase.
Variables
Write local variables just as you would a CSS declaration, but always include them first.
.example {
@base: 20px;
height: @base;
width: @base;
margin: @base/2;
}
Write global variables just as you would a CSS declaration, but optionally include one line break between related variables. It is also helpful to prefix related variables with a common name.
Remember that variables can also be called before they are declared, e.g., you could use the variable @color
on line 1 even though it is not declared until line 10.
@font-color: #000;
@font-size: 1rem;
@font-style: normal;
@font-bold: 'Open Sans Bold', @font-stack;
@font-italic: 'Open Sans Italic', @font-stack;
@font-stack: 'Helvetica', 'Arial', sans-serif;
@base-margin: 2rem;
@base-padding: 1rem;
@base-border: 0.25rem solid;
@base-border-radius: 0.125rem;
Lastly, it is a best practice to include all variables in a seperate stylesheet titled ui-variables.less
and import that stylesheet.
Do not include the .less
file extension.
@import 'partials/ui-variables';
Functions
Documentation in progressMixins
Documentation in progressNesting
Avoid nesting in LESS and Sass for the sake of it.
/* Bad */
.container {
ul {
li {
a {
&:hover {
}
}
}
}
}
While it might make sense within the LESS document to write selectors this way, it will result in inefficient CSS.
.container { ... }
.container ul { ... }
.container ul li { ... }
.container ul li a:hover { ... }
CSS
Always follow the [W3 Specifications][W3-CSS-Spec] for CSS properties and values. If you need to check browser support of a specification, [caniuse.com][resource-caniuse-css] is an invaluable resource.
Glossary of Terms Used
The property is an identifier with a human readable name, that defines which feature is considered by the engine. The value describes how the feature defined by the property must be handled by the engine. A declaration is a property and value pair; declations are grouped together in blocks. Different declarations are applied to different parts of the document by using selectors. The selector-declaration pair is known as ruleset, or often just simply a rule.
General CSS Guidelines
- In order to guarantee that code renders the same in any environment, use soft tabs with two spaces.
- Nested elements should be indented once (two spaces).
- Include one space after the
:
for each declaration. - Each declaration should be written on its own line and indented once (two spaces).
- End each declaration with a semi-colon. The last declaration is optional, but your code is more error prone without it.
- Never use the
@import
method; as stylesheets can only load one at a time, this method will result in longer load times.
Inline Styles
Optionally use inline styles to load declarations for content "above the fold". This is only an advantage if your CSS document is very small. It is disadvantageous and inconvenient for larger stylesheets.
<style>
...
</style>
Style Attribute
Although it is very common to do so, avoid using the style attribute on HTML elements in order to prioritize CSS delivery. In addition, it is against the Content Security Policy of W3. On occasion, it is appropriate, but should be avoided 90 percent of the time.
<!-- Avoid -->
<span style="background-color:#fff; color:#555;"></span>
Declarations, properties, and values
- Avoid specifying units for zero values, e.g.,
margin: 0;
instead ofmargin: 0px
; - Use shorthand whenever possible, e.g.,
font
instead offont-size
andfont-family
. - Use
!important
when necessary, but avoid repeated use. - Use single quotes and never double quotes.
- Stay consistent with units, e.g., do not use a mixture of REM and PX for typography, only use one or the other.
- Do not include a line-break after related declarations.
- Separate unrelated declarations with one line-break.
.example {
font: normal 12px "Arial";
margin: 0 5px 5px 0;
}
.example-2 { ... }
.example-3 { ... }
.unrelated-declaration { ... }
Declaration Order
Start from the "outside" and work "back in". Group related properties in the following order:
- Positioning
- Box model
- Typographic
- Visual
- Functional
- Pseudo-elements/classes (LESS and Sass only)
- Nested rulesets (LESS and Sass only)
Positioning comes first because it declares the nature of an element. The box model comes next as it dictates the dimensions and placement of an element. Typography and visual declaration declarations take place on the "inside" of the element and generally do not affect the "outside". Functional declarations (animations, transitions, transforms, etc.) are last. If you are writing LESS or Sass, include (after one full line-break), your nested rules and pseudo elements last. In the case that a declaration contains the content
property, include it first.
For a complete list of properties and their order, use [Recess][resource-recess].
.declaration-order {
content: '';
/* Positioning */
position: relative;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
/* Box Model */
display: block;
float: left;
width: 100px;
height: 100px;
/* Typography */
font: 13px "Arial";
color: #000;
/* Visual */
background: #fff;
border: 1px solid;
/* Functional */
transition: 1s ease;
/* Misc. LESS or Sass */
&:hover { opacity: 0.5; }
&:nth-of-type(2) { color: #555; }
}
Single Declarations
In the case where a rule includes on one declaration, remove line breaks for readability and faster editing. Include one space after the opening bracket and one before the closing bracket.
.class-1 { opacity: 1; }
.class-2 { opacity: 0; }
Optionally, you could drop the semicolon, but this can be error-prone and is not suggested.
.class-1 { opacity: 1 }
.class-2 { opacity: 0 }
Color Properties and Values
Always use either RGBA or RGB color values whenever possible. Write values in all lowercase with no space.
color: rgba(72,74,76,1);
color: rgb(72,74,76);
When writing hex values, use all lowercase values, e.g., #fff
, and shorthand whenever possible, e.g., #fff
instead of #ffffff
. If using LESS and Sass, always define variables for commonly used colors and write functions with no spaces, e.g., fadeOut(@red,25%);
.
@primary-grey: #555;
@primary-white: #fff;
color: @primary-white;
background: fadeOut(@primary-grey,50%);
Browser Prefixes
Use -webkit-
, -moz-
, -ms-
, and -o-
, in that order. Always also include an un-prefixed copy of the base property last and align the prefixed properties to the same column.
-webkit-transform: ... ;
-moz-transform: ... ;
-ms-transform: ... ;
-o-transform: ... ;
transform: ... ;
To determine which properties require prefixes, refer to [caniuse][resource-caniuse-css]. If you use a taskrunner, [autoprefixer][resource-autoprefixer] is very useful, as is Lea Verou's pollyfill, [prefix-free][resource-prefixfree].
Selectors
- Use class selectors and avoid ID selectors
- Never use the universal selector
- Avoid combined type selectors, also known as descendant selectors, e.g.,
ul li a
- Always group several selectors that share the same declarations together, e.g.,
h1, h2, h3, h4, h5, h6
. - Follow the W3 specification on selectors
Class Selectors
Unless a specific case requires otherwise, always use class selectors. Do not combine class selectors with type selectors, e.g., h1.bold
; instead use .heading-bold
.
ID Selectors
Avoid ID selectors and instead use class selectors. Never combine ID selectors with type selectors, e.g., h1#primary
.
Type selectors
Avoid using lengthy type selectors, e.g., ul li a
. Since browsers read selectors from right to left, not left to right as humans do, longer selectors can greatly impact performance.
Pseudo-elements and Pseudo-classes
When grouping pseudo-elements and classes with other selectors, include them last.
a,
a:visited,
a:nth-of-type(2) { ... }
Always declare the pseudo elements :before
first and :after
second, but declare them after the element they effect. Include the content
property first in the declaration.
a { ... }
a:before { ... }
a:after {
content: 'attr(href)';
color: red;
border: 1px solid;
}
When combining pseudo-classes, use two colons for the second class, e.g., a:visited::hover
.
Link and Dynamic Pseudo-classes
Always declare rules for the selectors :hover
, :active
, :focus
, :visited
, respectively. The selector :link
is optional, as the a
type selector is equally as effective; only use :link
and :visited
on links.
Notes on Code Robustness
An important part of both HTML and CSS code is how specific and robust it is. Some call this writing code as a "human-readable medium", but in the end, all text code is readable by humans. Everyone can read code, but only few can fully understand it. Rather than making code readable, focus on writing code in which a developer can understand its functions.
In order to write understandable code, it must be robust and set in a strong foundation. From that strong foundation, you can add a level of specification through class names and comments. This process is known as self-documenting code: source code that is that follows loosely defined conventions for naming and structure. These conventions allow for developers to effectively use the source code without previous knowledge of its specification, design, or behavior.
Good, extensive documentation is key to robust code. More often than not, extensive documentation cannot be expressed through just source code. While robust object-oriented class names and specific comments certainly do help, they should not be the only form of documentation.
Class Names
- Keep classes lowercase and use dashes (not underscore or camelCase). Dashes provide for readability and natural breaks in related classes, e.g.,
.btn
and.btn-danger
. - Be specific and concise when naming classes. Use meaningful names that describe the action or functionality of a class rather than is appearance, e.g.
.btn-danger
instead of.btn-red
. - Abbreviate some class names, but make sure anyone can understand the class, e.g.,
.btn
instead of.button
. - Prefix classes based on the closest parent element or base class.
- Always use a base class for elements with different states. If you have a success and a failure label, make the base class
.label
and the classes.success
and.warning
will give it the specific styles needed for different states.
/* Unintuitive */
.u { ... }
.uContainer { ... }
.label_red { ... }
/* Magical */
.upload-item { ... }
.upload-item--container { ... }
.upload-label.warning { ... }
HTML Comments
In an HTML document with few lines of code, do not place comments by closing tags. In larger HTML documents, where there may be multiple closing tags of the same element include a comment containing a backslash and the class/ID name; this will help prevent human error in when making changes in development. If a description is necessary, include a colon and a short summary of element after the class/ID name. Generally, however, you should include descriptions in the stylesheet; long descriptions can diminish readability of HTML documents.
<div class=header>
<div class=example-div-1>
<div class=example-div-2>
...
</div><!-- /example-div-2 -->
</div><!-- /example-div-1 -->
</div><!-- /header: Primary header for all pages-->
CSS Comments
Never simply reiterate a component or selector name. Always write short comments in the third person, present tense. Longer comments may be written in any person or tense.
/* Bad </3 */
/* Page Header */
.page-header {
...
}
/* xD */
/* .page-header: Contains the primary header elements */
.page-header {
...
}
Both LESS and Sass allow in-line comments; use these to add notes after certain properties.
.example {
@base: 25px;
width: round((@base*2)/3.14); // => 16.0px
background: #555; // background will match footer
}
Never feel limited to one line with comments; use as many lines as necessary to explain the function/purpose of a declaration.
Separate stylesheets into sections with three line-breaks and a comment. Within this comment include the title of the section and a brief description less than forty characters. If you prefix the title of the sections with a unique character not used anywhere else in the code, you can easily search for different sections, e.g. search for $CONTENT-PAGE
and this will only result with the section title, no classes will be returned.
...
/* ------------ -----------
$SEARCH-PAGE
All rules for the default search page
----------- ------------ */
.search-page--header {
...
}
Sources
- "CSS Guide" by Mark Otto
- "CSS Guidelines" by Harry Roberts
- "Comments Are More Important Than Code" by Jef Raskin