-
Notifications
You must be signed in to change notification settings - Fork 1
sass coding guidelines
Best practices and guidelines for writing sane, consistent, maintable and scalable Sass (CSS).
It's actualy a mash-up of these documents:
- CSS Guidelines (Harry Roberts)
- Google HTML/CSS Style Guide
- Primer Guidelines (GitHub)
- Principles of writing consistent, idiomatic CSS (Nicolas Gallagher)
- Sass Guidelines (Hugo Giraudel)
-
Strictly enforce the agreed-upon style;
All code should look like a single person typed it. -
Optimize (minified) code for bytesize;
but keep the source maintainable, readable and understandable first.
Use SCSS syntax, there're many good reasons:
- it's an extention of CSS syntax,
- code is legible/easy to understand,
- every valid CSS3 stylesheet is a valid SCSS file with the same meaning,
- SCSS understands most CSS hacks and vendor-specific syntax.
- Use whitespace to improve readability.
- Be consistent across the entire source codebase.
- Never mix spaces and tabs for indentation.
Install EditorConfig plugin to your editor/IDE to help maintain the basic whitespace conventions.
Otherwise set your IDE configuration according to project .editorconfig file.
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.
- Use component skeleton to write down new Sass component.
- Use SassDoc 1.x C-style comments (
/** */) for custom Sass extends, functions and mixins.
// =============================================================================
// Section comment block (not rendered)
// =============================================================================
.section {}
// Sub-section comment block (not rendered)
// =============================================================================
.subsection {}
/**
* Long comment with description (rendered).
*
* 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.
*
* 1. Set height.
* 2. Disable spasmodic transition in Opera 12 (+ older).
*
* 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.
*/
.selector {
height: 0; /* 1 */
-o-transition: none; /* 2 */
}
// Multiline comment (not rendered)
// @link https://github.com/mvcss/mvcss/blob/master/core/_helpers.sass
@function em($target, $context: $base-font-size) {
..
}
// Basic comment (not rendered).
$variable: value;
// =============================================================================
// Mixins
// =============================================================================
/**
* Sets element maximum dimensions.
*
* @param {Number} $width (100%)
* @param {Number} $height (100%)
*/
@mixin max($width: 100%,$height: 100%) {
..
}
/**
* Sets element minimum dimensions.
*
* @param {Number} $width (0)
* @param {Number} $height (0)
*/
@mixin min($width: 0, $height: 0) {
..
}
// =============================================================================
// Extends
// =============================================================================
/**
* Truncates string with ellipsis.
*/
%truncate {
..
}
/**
* Provides `microfix` for group of elements.
*
* @requires {Mixin} microfix
*/
%group {
..
}
// =============================================================================
// Functions
// =============================================================================
/**
* Gets map of colors operations and their values to pass to transform
* `$b` color from `$a` color.
*
* @author Hugo Giraudel
* @link http://goo.gl/9BRthi
*
* @param {Color} $a
* @param {Color} $b
* @return {Map} - Map of color operations to do in order to
* transform `$b` from `$a`
*/
@function color-diff-get($a, $b) {
..
}
/**
* Converts `px` to `em` units.
*
* @param {Number} $target
* @param {Number} $context - Context `font-size`
* @return {String}
*
* @example scss
* .selector {
* font-size: em(24);
* }
*/
@function em($target, $context: $base-font-size) {
..
}
The chosen code format must ensure that code is:
- easy to read,
- easy to 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 (and follow Declaration order).
- Use one level of indentation for each declaration.
- Include a single space after the colon of a declaration.
- Place closing braces of declaration blocks on a new line.
- Place the closing brace of a ruleset in the same column as the first character of the ruleset.
- Use __lowercase and shorthand hex value__s;
e.g.#aaa. - Use hex color codes
#000unless usingrgba(). - Use double quotes;
e.g.content: "",background-image: url("foo.svg"). -
Quote attribute values in selectors;
e.g.input[type="checkbox"]. - Include a semi-colon at the end of the last declaration in a declaration block.
- Avoid unnecessary shorthand declarations.
- Last pair of a
listormapshould have a trailing comma if multilines. -
Do not use vendor prefixes if not necessary;
autoprefixer does the heavy lifting for you. - Do not use standalone browser hacks - use them as
@mixin(s).
// Bad
// Set button background.
$button-background: (
disable: #d8ddf0, // disabled
initial: $gray--periwinkle
);
.selector-a, .selector-b{
zoom: 1; color: #FFFFFF;
padding: 0 0 10px 0px;
border: solid 1px #0f0;
@include foo;
.selector-c{background: red; margin: 5px 0px}
@extend foo;
content: '';
background-image: url("image.png") }
// Good
// Set button background.
$button-background: (
disable: #d8ddf0, // disabled
initial: $gray--periwinkle,
);
.selector-a,
.selector-b {
@extend foo;
@include foo;
$local-variable: 10;
background-image: url("image.png");
border: 1px solid #0f0;
color: #fff;
content: "";
padding-bottom: 10px;
zoom: 1;
.selector-c {
background-color: red;
margin: 5px 0;
}
}
Long, comma-separated property values (gradients or shadows) or @mixin parameters can be arranged across multiple lines in an effort to improve readability and produce more useful diffs.
Aim for max 80 columns per line.
.selector {
background-image:
linear-gradient(#fff, #ccc),
linear-gradient(#f3c, #4ec);
box-shadow:
1px 1px 1px #000,
2px 2px 1px 1px #ccc inset;
}
@mixin foo(
$family,
$file,
$style: normal,
$weight: normal,
$cache-buster: ""
) {
@font-face {
...
}
}
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.
.selector-1 { width: 10%; }
.selector-2 { width: 20%; }
.selector-3 { width: 30%; }
- Use alphabetical ordering (simplicity and ease-of-maintenance).
- Place
@extendstatements on the first lines of a declaration block. - Group
@includestatements at the top of a declaration block (right after@extendstatements). - Place local variables at the top of declaration block (right before
@extend/@includestatements). - Place
@mediaqueries at the bottom of declaration block.
- Define
font-sizein pixels and use relevant mixins where needed. - Use unitless
line-height. - Avoid specifying units for zero values;
e.g.margin: 0;instead ofmargin: 0px;. - Do not omit leading zeros for units;
e.g.margin: 0.5em;instead ofmargin: .5em;.
Follow these rules to avoid completely non-reusable code due to the extreme specificity of selectors.
Follow the updated The Inception Rule:
Don’t go more than three levels deep!
In other words, do not overuse Sass Nested rules feature, aim for three levels and nest rules as few as possible.
Do not use IDs.
There's no benefit to prefer ids to classes at all.
/* Bad */
#component {}
/* Bullshit */
#component-a {
#component-b {}
}
/* Good */
.component {}
If possible, use only selectors that includes semantics.
A span or div holds none. A heading has some. A class has plenty.
Avoid element specific selectors.
/* Bad */
span.module {}
/* Good */
.module {}
Try to avoid the rule and use it carefully.
Prefix layer/component with its name abbreviation (3 chars at least).
That naming convetion makes it easier for developer to localize the component (besides sourcemaps).
Naming is fully based on BEM methodology.
- Use lowercase hyphen/lodash-separated semantic names.
/**
* Component ComponentName.
*
* @requires {function} function
* @requires {mixin} mixin
* @requires {placeholder} %placeholder
* @requires {variable} $variable
* @requires component
*/
// =============================================================================
// ComponentName
// =============================================================================
// .component {}
/**
* Modifiers.
*/
// .component--modifier {}
// .component {
// &.--modifier {}
// }
/**
* States.
*/
// .is-component-state {}
// .component {
// &.is-state {}
// }
/**
* Context.
*/
// .has-component {}
/**
* Animations.
*/
// @keyframes component-animation {}
// =============================================================================
// Subcomponents
// =============================================================================
// SubcomponentName
// =============================================================================
// .component__subcomponent {}
- Use lowercase hyphen-separated semantic names.
- Two hyphens are allowed for naming module modifiers variables (CSS classes naming convetions analogy).
- Use full component/layer names as an variable prefix (unlike CSS class names).
- Use Sass maps for setting component states.
// =============================================================================
// Variables
// =============================================================================
// Set component property.
$component-property: value;
// Set component property.
$component-property: (
active: , // pressed
disable: , // disabled
focus: , // focused
hover: , // hovered
initial: ,
);
// Set component subcomponent property.
$component-subcomponent-property: value;
// Set component modifier property.
$component--modifier-property: value;