Skip to content

Instantly share code, notes, and snippets.

@carwin
Created March 5, 2013 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carwin/5093583 to your computer and use it in GitHub Desktop.
Save carwin/5093583 to your computer and use it in GitHub Desktop.
Drupal 8 CSS formatting standards, re-written to adhere to RFC documentation standards. Proposed by sun in http://drupal.org/node/1891580#comment-7128434. Original D8 CSS formatting standards document is here: http://drupal.org/node/1887862
<h2>Table of Contents</h2>
<a href="#whitespace">Whitespace</a>
<a href="#comments">Comments</a>
<a href="#format">Format</a>
<a href="#miscellaneous">Miscellaneous</a>
<a href="#example">Practical Example</a>
<h3><a name="terminology"></a>Terminology</h3>
For those unfamiliar with <a href="http://www.w3.org/TR/CSS2/syndata.html#statements">CSS terminology</a>, these are the concise terms used in these standards.
<code>
selector {
property: value;
}
</code>
<a name="rule-set"></a>A <strong>rule set</strong> (also called a <strong>rule</strong>) consists of a selector followed by a declaration block.
<a name="selector"></a>The <strong>selector</strong> consists of everything up to (but not including) the first left curly brace (<code>{</code>).
<a name="block"></a>A <strong>declaration block</strong> starts with a left curly brace (<code>{</code>) and ends with the matching right curly brace (<code>}</code>). In between there must be a list of zero or more semicolon-separated (<code>;</code>) declarations.
<a name="declaration"></a>A <strong>declaration</strong> consists of a <strong>property name</strong>, followed by a colon (<code>:</code>), followed by a <strong>value</strong>.
<h2><a name="whitespace"></a>Whitespace</h2>
<h3><a href="indentation"></a>Indentation</h3>
Using tabs for indentation leads to inconsistent display of the source code, since many text editors and most text viewers (like web browsers) cannot have their “tab size” configured.
Lines that need indentation MUST use 2 spaces for each level of indentation, the same standard as Drupal’s PHP and JavaScript code.
<ul>
<li>Declarations (property/value pairs) MUST be indented one level relative to their selector.</li>
<li>Rulesets within a media block or a media query MUST be indented one level relative to the media statement.</li>
<li>Comments MUST be indented the same amount as the declaration or ruleset they describe.</li>
</ul>
<code>
@media print {
/* This line is indented with 2 spaces, 2 spaces x 1 level of indentation. */
.example {
/* This line is indented with 4 spaces, 2 spaces x 2 levels of indentation. */
padding: 0;
}
}
</code>
<h3><a href="line-endings"></a>Line endings</h3>
There MUST NOT be any whitespace (spaces or tabs) at the end of lines. This means blank lines should also not contain any spaces or tabs. Inconsistent trailing whitespace can add lines to diffs/patches and makes changes harder to notice.
All text files MUST end with a single blank line. This makes git commits easier to read since it's clearer what is being changed when lines are added to the end of a file and it avoids the verbose <code>\ No newline at end of file</code> warning in patches.
Files MUST be formatted with Unix line endings (a newline character, denoted as <code>\n</code> or <code>LF</code>), which is also the default in Mac OS X. Do not use Windows line endings (a carriage return plus a newline, denoted as <code>\r\n</code> or <code>CRLF</code>).
Tip: configure your editor to “show invisibles”. This will allow you to eliminate end-of-line whitespace, eliminate unintended blank-line whitespace, and avoid polluting commits.
Drupal 8 includes an <a href="http://editorconfig.org/">EditorConfig</a> file in <a href="http://drupalcode.org/project/drupal.git/tree/refs/heads/8.x">its root directory</a> to help maintain these whitespace conventions.
<h2><a name="comments"></a>Comments</h2>
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 guessing as to the purpose of uncommon or non-obvious code.
To stay consistent with the rest of Drupal's code base, we borrow some of the CSS comment styles from the <a href="http://drupal.org/node/1354">Doxygen and comment formatting conventions</a> for PHP files.
<h3><a name="file-comments"></a>File comments</h3>
Each file MUST start with a comment describing what the file does. For example:
<code>
/**
* @file
* Short description describing the file.
*
* 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.
*/
</code>
Note that a blank line MUST follow a @file documentation block. And line-lengths SHOULD be kept to 80 columns. For more information, see the <a href="http://drupal.org/node/1354#files">PHP file comment standards</a>.
<h3><a name="multi-line-comments"></a>Multi-line comments</h3>
When describing a ruleset or set of rulesets, any comment that requires 2 or more lines (wrapped to 80 characters) MUST follow the Doxygen comment style (also called a “docblock”).
<code>
/**
* 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.
*/
.example-rule {
}
</code>
Place the comment on the line immediately above the ruleset (or rulesets) it describes. Place a blank line before the docblock comment. See the <a href="http://drupal.org/node/1354">Doxygen and comment formatting conventions</a> for more info.
<h3><a name="single-line-comments"></a>Single-line comments</h3>
When describing a property or ruleset, any comment that can be written inside the 80 character line length limit MAY use a simple CSS comment style.
<code>
.example {
/* Override the default margins. */
margin: 0;
}
/* The example's item styling. */
.example--item {
display: inline;
}
</code>
Place the comment on the line immediately above the property or ruleset it describes. The comment should be indented the same amount as the property or ruleset it describes.
If the comment is describing a ruleset, place a blank line before the comment.
<h3><a name="rtl-comments"></a>Comments for Right-To-Left Languages</h2>
It is common for RTL language websites to have their designs flipped in the left/right direction. To support this requirement, Drupal will look for and load a corresponding &lt;file&gt;-rtl.css CSS file if the requested page is for a right-to-left language. For example, Drupal will load a system.admin-rtl.css file in addition to a system.admin.css file. This allows for CSS properties that have asymmetry in the left/right direction to be swapped in the -rtl CSS file. Such properties MUST be marked with a <code>/* LTR */</code> comment.
If we have an example.css:
<code>
.example-rule {
float: left; /* LTR */
margin-right: 1.5em; /* LTR */
padding: 0 0.25em;
}
</code>
The above properties will be overridden when the example-rtl.css is loaded:
<code>
.example-rule {
float: right;
margin-left: 1.5em;
margin-right: 0;
}
</code>
See also: http://drupal.org/node/132442#language-rtl
As a rule of thumb, an <code>/* LTR */</code> comment SHOULD be included:
<ul>
<li>when the keywords, 'left' or 'right' are used in a property, e.g. <code>float: left;</code></li>
<li>where an unequal margin, padding or borders on the sides of a box, e.g. <code>margin-left: 1em;</code> or <code>padding: 0 0 0 2em;</code></li>
<li>when the direction of the language is specified, e.g. <code>direction: ltr;</code></li>
</ul>
<h2><a name="format"></a>Format</h2>
Our CSS formatting ensures the code is easy to read, easy to clearly comment, minimizes the chance of accidentally introducing errors, and results in useful Git diffs and blames.
<h3><a name="rule-sets">Rulesets</h3>
<ul>
<li>Use one selector per line when a ruleset has a group of selectors separated by commas.</li>
<li>The opening brace (<code>{</code>) of a ruleset’s declaration block MUST be on the same line as the selector (or the same line as the last selector in a group of selectors.) The opening brace MUST include a single space before it.</li>
<li>The closing brace (<code>}</code>) of a ruleset MUST be placed in the same column as the first character in the selector of the ruleset.</li>
<li>Include one declaration per line in a declaration block.</li>
<li>Each declaration MUST be indented one level relative to its selector.</li>
</ul>
<h6>Example Ruleset</h6>
<code>
.selector-alpha,
.selector-beta {
counter-reset: section;
text-transform: small-caps;
}
</code>
<h3><a name="properties">Properties</h3>
<ul>
<li>In a declaration, the property name MUST be immediately followed by a colon, then a single space, and then the property’s value.</li>
<li>A terminating semi-colon MUST be included at the end of all declarations, including the last declaration in a declaration block.</li>
<li>When hex values are used for colors, lowercase MUST be used and, if possible, the shorthand syntax SHOULD be adhered to, e.g. <code>#aaa</code>. Colors MAY be expressed with any valid CSS value, such as hex value, color keyword, rgb() or rgba(). Note that IE8 does not support all color syntaxes and will require a fallback value.</li>
<li>For property values that require quotes, double quotes instead MUST be used in place of single quotes, e.g. <code>font-family: "Arial Black", Arial, sans-serif;</code> and <code>content: " ";</code>.</li>
<li>Attribute values MUST be quoted in selectors, e.g. <code>input[type="checkbox"]</code>.</li>
<li>Where allowed, specifying units for zero-values SHOULD be avoided, e.g. use <code>margin: 0;</code> instead of <code>margin: 0px;</code>.</li>
<li>A space MUST follow each comma in comma-separated property or function values.</li>
<li>Spaces MUST NOT be used around the parentheses in a function, e.g. <code>color: rgba(0, 0, 0, 0.8);</code></li>
</ul>
<h6>Example Properties</h6>
<table>
<tr>
<td><code>display: block;</code></td>
<td>Basic syntax</td>
</tr>
<tr>
<td><code>color: #fff</code><br><code>color: #df7dcf</code></td>
<td>Use shorthand syntax for hexadecimal colors when possible<br>Always use lowercase</td>
</tr>
<tr>
<td><code>font-family: "Frutiger Ultra"</code></td>
<td>Use double quotes instead of single quotes</td>
</tr>
<tr>
<td><code>text-shadow: 0 0 2px #ddd</code></td>
<td>Do not attach units to zero-values</td>
</tr>
<tr>
<td><code>color: rgba(0, 136, 18, 0.8)</code></td>
<td>Spaces MUST follow commas in property or function values</td>
</tr>
</table>
<h3><a name="blank-lines">Blank lines</h3>
In most cases, rulesets SHOULD NOT be separated by a blank line. The exceptions to this are:
<ul>
<li>If a ruleset has a proceeding Doxygen-sytyle or single-line-style comment that describes it, place a blank line before the comment.</li>
<li>If two rulesets have no interleaving blank line, they must be logically related. If they are not logically related to each other, add a blank line and a comment describing the second ruleset.</li>
</ul>
<code>
/* A comment describing the ruleset. */
.selector-1,
.selector-2,
.selector-3[type="text"] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
display: block;
margin: 0;
font-family: Times, "Times New Roman", sans-serif;
color: #333;
background: #fff;
background: linear-gradient(#fff, rgba(0, 0, 0, 0.8));
}
/**
* A longer comment describing this ruleset. Note
* the blank line before the docblock.
*/
.selector-4,
.selector-5 {
padding: 10px;
}
/* This logical grouping of rulesets has no interleaving blank lines. */
.profile {
margin: 1em 0;
}
.profile__picture {
float: right; /* LTR */
}
</code>
<h3><a name="declaration-order"></a>Declaration order</h3>
The declarations in a ruleset SHOULD be ordered so that the purpose of the declaration block is most obvious. Clarity should be the guiding principle. We can help to achieve this goal by placing structurally important properties before others: positioning, box model, then other properties.
<ol>
<li>Positioning properties include: <code>position</code>, <code>float</code>, <code>clear</code>, <code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>, <code>direction</code>, and <code>z-index</code>.</li>
<li>Box model properties include: <code>display</code>, <code>[(max|min)-]height</code>, <code>[(max|min)-]width</code>, <code>margin</code>, <code>padding</code>, <code>border</code> and their various longhand forms (<code>margin-top</code>, etc.) Plus <code>box-sizing</code>.</li>
<li>Other declarations.</li>
</ol>
Within each of the above groups, properties MAY be grouped alphabetically or grouped with like properties next to each other, e.g. putting font and text properties next to each other. Drupal’s coding standards are purposefully vague here because there is no consensus on this issue (as of 2013), but we respect each other’s abilities and preferences.
Vendor prefixed properties MUST be directly before their non-prefixed version. This allows the official version of the property to override any inconsistencies in the vendor-prefixed versions once those browsers implement the official property. If browser bugs or cross-browser issues necessitate any deviation from this ordering, it MUST be clearly documented.
Again, the order of properties are meant to reinforce the purpose of the ruleset. As such, <strong>it is much more important to add comments to the ruleset then to worry about property ordering.</strong>
<code>
.selector {
/* Positioning declarations */
position: absolute;
top: 0;
left: 0;
z-index: 10;
/* Box model declarations */
display: inline-block;
width: 100px;
padding: 10px;
border: 1px solid #333;
/* Other declarations */
background: #000;
color: #fff;
font-family: sans-serif;
font-size: 1.1em;
}
</code>
Tools like <a href="http://csscomb.com/">CSScomb</a> may help with automating the order of properties.
<h3><a name="exceptions"></a>Exceptions and slight deviations</h3>
Large blocks of single declarations MAY use a slightly different, single-line format. In this case, a space should be included after the opening brace and before the closing brace.
<code>
.selector-1 { width: 10%; }
.selector-2 { width: 20%; }
.selector-3 { width: 30%; }
</code>
Long, comma-separated property values—such as collections of gradients or shadows MAY be arranged across multiple lines in an effort to improve readability and produce more useful diffs.
<code>
.selector {
background-image:
linear-gradient(#fff, #ccc),
linear-gradient(#f3c, #4ec);
box-shadow:
1px 1px 1px #000,
2px 2px 1px 1px #ccc inset;
}
</code>
<h2><a name="miscellaneous"></a>Miscellaneous</h2>
<h3>@charset statements</h3>
Character set statements (like <code>@charset "UTF-8";</code>) are only valid if they are at the very top of a CSS file. Since Drupal’s CSS aggregator combines multiple CSS files into one file, Drupal will strip all <code>@charset</code> statements so that the aggregated file remains valid CSS.
This means CSS files MUST NOT include any <code>@charset</code> statements. The default encoding for CSS files is UTF-8. Any CSS comments or <code>content</code> property values MUST be encoded with UTF-8.
<h2><a name="example"></a>Practical example</h2>
An example of various conventions.
<code>
/**
* @file
* Layouts for this theme.
*/
/**
* 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.
*/
.grid {
height: 100%;
/* Remove inter-cell whitespace */
font-size: 0;
/* Prevent inline-block cells wrapping */
white-space: nowrap;
}
/**
* Grid cells
*
* No explicit width by default. Extend with '.cell-n' classes.
*/
.cell {
position: relative;
display: inline-block;
overflow: hidden;
box-sizing: border-box;
height: 100%;
/* Set the inter-cell spacing */
padding: 0 10px;
border: 2px solid #333;
vertical-align: top;
/* Reset white-space */
white-space: normal;
/* Reset font-size */
font-size: 16px;
}
/* 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;
}
</code>
&nbsp;<br>
<hr>
The text of this guideline was originally based on the <a href="https://github.com/necolas/idiomatic-css"><i>Principles of writing consistent, idiomatic CSS</i></a> by Nicolas Gallagher.
This document attempts to follow the RFC Document Style.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment