-
Notifications
You must be signed in to change notification settings - Fork 5
CSS coding guidelines
The rules defined in the Google CSS style guide are the same as adidas company has defined. The Google style guide is a good reading to know CSS guidelines and good practices as well.
These guidelines are also applied if the code is written using CSS preprocessors, such as LESS or SASS.
Another good document for CSS good practices is the code guide by @mdo.
List of main rules, customized ones and examples.
- Always use classes instead of identifier selectors.
- Use meaningful names but short as possible.
- Use namespaces in order to wrap classes inside a blocks to avoid collisions among private classes defined in different modules.
- Using for example the module name to which affects as prefix.
- Naming conventions:
kebab-case
.- Lowercase names.
- Use
-
as separator.
Note: using BEM methodology the _
separator is a valid character, see BEM - Block Element Modifier methodology section.
/* invalid CSS class-names and selector */
#moduleNameClassName {
color: #fff;
}
.moduleNameClassName {
color: #fff;
}
.module_name_class_name {
color: #fff;
}
/* valid CSS class-names */
.module-name-class-name {
color: #fff;
}
.module-name-class-name .element-class {
color: #fff;
}
The code comments depend on if the code is plain CSS or it is preprocessed:
-
CSS code:
- Use only the multi-line type comments.
- One line comments are not supported by CSS parsers.
-
Preprocessed CSS code:
- Simple and multi-line comments are allowed, however, it is recommended to use the one line style.
-
For one line comments, add a whitespace before the code.
-
For multiple lines comments, open and lose the comment in a previous and the next line, and add a whitespace before the code.
// CSS: invalid class comment
.module-name-class-name {
color: #fff; // Invalid CSS property comment.
}
/*
* CSS: valid class comment.
* Long description broken in multiple lines.
*/
.module-name-class-name {
color: #fff; /* CSS: valid property comment */
}
/* CSS: valid class comment */
.module-name-class-name {
color: #fff; /* CSS: valid property comment */
}
// Preprocessed CSS: valid class comment
.module-name-class-name {
color: #fff; // Preprocessed CSS: valid property comment
}
It is a good practice to separate different classes using blank lines in order to have a more understandable CSS.
- Add a blank line after every class.
- For classes that depends on the same selector is recommended as well but not mandatory.
- Properties indented using 2 whitespaces -1 tab-.
/* using CSS with the same class as selector (no blank lines) */
.module-name-class-name {
color: #fff;
}
.module-name-class-name .element-class {
color: #fff;
}
.module-name-class-name .other-element-class {
color: #fff;
}
/* different classes */
.module-name-class-name {
color: #fff;
}
.module-name-class-name .element-class {
color: #fff;
}
.other-module-name-class-name {
color: #fff;
}
Commented CSS code is now allowed in repositories, so, the commented code has to be removed or not pushed.
Note: if there is a important reason in order not to remove the commented code, it has to be added to the commented block with a TODO
.
- CSS code: use only the multi-line type comments.
- Single line can open and close the comment in the same line, adding a whitespace after and before respectively.
- For multiple lines, open and lose the comment in a previous and the next line, and add a whitespace before the code.
- Preprocessed CSS code: use only one line comments.
- Add a whitespace before the code.
/* CSS: */
/*
* TODO: activate when ...
* .other-module-name-class-name {
* color: #fff;
* }
*/
// Preprocessed CSS:
// TODO: activate when ...
// .other-module-name-class-name {
// color: #fff;
// }
The CSS code is not the most maintainable one, so, applying some good practices it could be more maintainable and easier to understand.
- Use meaningful class names.
- Use relative unit as much as possible to be able to create flexible layouts.
- The font size is a good base to define the measures of the elements using
em
/rem
.
- The font size is a good base to define the measures of the elements using
- With preprocessors:
- Use meaningful variable names containing the block and the property or properties to which refer.
- If a value is related to another one, create a variable and compute the values based on it.
- Use autoprefixer to avoid to write browser custom prefixes and define which versions have to be compatible.
One of the guides to write good class names, to be easily reused, is BEM - Block Element Modifier methodology.
According to the BEM webpage: it is a methodology that helps you to create reusable components and code sharing in front-end development.
It is a methodology to take into account, because it uses the separators __
and --
to define blocks and behaviors respectively, so, it is easy to understand the elements to which that class can be applied and what will be the behavior of them.
- Block: just the name of the high level structure.
- Example:
.action-bar
.
- Example:
- Element: a specific part of a block.
- Example:
.action-bar__button
.
- Example:
- Modifier: a specific behavior or state of a block/element.
- Example:
.action-bar__button--success
.
- Example:
For more information, read the BEM introduction.
All the CSS basic rules are applied also to the preprocessed CSS languages, such as LESS or SASS, however, they define other useful aspects with some specific rules.
On the other hand, PostCSS is a tool to complete tool to manage the different language preprocessors: "transform CSS with the power of JavaScript. Auto-prefixing, future CSS syntaxes, modules, linting and more are possible with hundreds of PostCSS plugins".
Basically, PostCSS can be written as pure CSS, hence applying the rules defined for naming, indentation, etc. Aside from that, the combination of selected plugins provide a set of features that most preprocessors have.
The next rules can be applied, almost, to all the CSS languages.
Most of the preprocessed CSS languages use the same structure for the CSS, which do it more understandable and reduce the amount of code. This structure is based on nesting, and it is mandatory to be used.
- Add always a blank line after properties if the next element is a class definition.
- The whitespaces and blank line rules are also applied to this structure.
- Indentation of inner blocks with 1 tab -2 whitespaces-.
- Use
&
to avoid to write the same name if the children classes repeat it.
Plugin for PostCSS: postcss-nested.
/* code written in CSS */
.module-name .module-name-class-name {
color: #fff;
}
.module-name .module-name-class-name .element-class {
color: #fff;
}
.module-name .module-name-class-name .element-class:hover {
color: #ccc;
}
.module-name .module-name-class-name .other-element-class {
color: #fff;
}
// previous code written with preprocessed CSS
.module-name {
&-class-name {
color: #fff;
.element-class {
color: #fff;
&:hover {
color: #ccc;
}
}
.other-element-class {
color: #fff;
}
}
}
PostCSS provides also conditional and loop structures which improve the language.
$columns: 4;
.grid {
@if $columns < 3 {
background-color: #fff;
}
@else {
background-color: #eee;
}
}
// result
.grid {
background-color: #eee;
}
$columns: 4;
@for $i from 1 to $columns {
.class-name-$i {
width: $(i)px;
}
}
// result
.class-name-1 { width: 1px; }
.class-name-2 { width: 2px; }
.class-name-3 { width: 3px; }
.class-name-4 { width: 4px; }
The use of the importing feature, usually @import
, is very powerful, because it allows to load the content of another file in the current one, so, it can be used to manage all the CSS files.
It can load simple CSS files, preprocessed files, coming from the source code structure as well as from the node_modules
folder to load CSS from third party libraries.
- Place the imports always on top of the scope.
- If the scope is inside a class to be used as namespace, place them right after the class definition.
- If there are no dependencies, sort them alphabetically.
- The imports can be grouped in blocks according to their purpose just adding a blank line.
- End all the imports with
;
. - Omit the extension of the file if it is the same as the preprocessor used.
// style.scss
@import "~design-library/css/design.css";
@import "~design-library/css/design-dark.css";
@import "variables";
@import "mixins";
.application {
@import "./modules/header/header";
@import "./modules/header/navigation-bar";
.class-name {
...
}
}
Variables can be used for calculations, conditions, mixins, etc. It is recommended to create them in a separate file which can be imported by other stylesheets and be shareable.
In PostCSS, variables are introduced with the plugin postcss-simple-vars, check this repository for full documentation.
- Use meaningful names.
- Use
kebab-case
to define the variable names. - Place each variable in a new line.
- End all the declarations with
;
. - Add a whitespace after the variable name (
:
). - Define inner variables if they only affect to a class and its children.
- Reuse the variables in the same variables file, or use operations if a variable depends on another one.
- Reuse variables in global variables files.
- Group the variables according to their purpose and use blank line to separate the blocks of code.
@import "colors";
@import "variables";
$button-size: 2em;
$button-bg-color: darken($color-primary);
.action-bar {
$action-bar-width: calc(100% - #{$global-padding});
$action-bar-line-height: 2.5em;
.container {
width: $action-bar-width;
line-height: $action-bar-line-height;
}
.button {
background-color: $button-bg-color;
width: $button-size * 2;
height: $button-size;
}
}
The mixins are useful structures to share CSS code among classes. However, the code of the mixin is just placed inside the class in compilation time, so, it is repeated as many times as the mixin is used.
The recommendation is to use mixins if the code generated depends on some value given as parameter. Else, create a class with the code.
Plugin for PostCSS: postcss-mixins.
Also, mixins allow transclusion, for that purpose, the mixin needs to use the at-rule @mixin-content
as a statement in order to apply the transcluded content.
It is also useful to know the extend
feature: postcss-extend.
// transclude mixin definition
@define-mixin transclude $text {
content: $text;
@mixin-content;
}
// transclude mixin usage
.foo {
content: 'mixin';
.bar {
@mixin transclude bar {
height: 100%;
&:hover {
border: 1px solid #fff;
}
}
}
}
// result
.foo {
content: 'mixin';
}
.foo .bar {
content: 'bar';
height: 100%;
}
.foo .bar:hover {
border: 1px solid #fff;
}
This feature helps the development process avoiding to use browser prefixes in the CSS properties, and also to transpile the same source code to be compatible with different browser versions.
- The developer forgets about the vendor prefixes because are automatically added in transpiling time.
- It reduces the source code.
- It makes the code compatible with different browser versions.
- It removes unnecessary prefixes if they are obsolete.
- If a rule has been accepted, the new release of the tool removes the not longer necessary prefixes.
Plugin for PostCSS: autoprefixer.
.tile {
transform: rotate(30deg)
}
// result
.tile {
-webkit-transform: rotate(30deg)
-ms-transform: rotate(30deg)
transform: rotate(30deg)
}
In order to check most of the style rules, there is a configuration using the stylelint tool for several CSS languages. According to its documentation: the linter is powered by PostCSS, so it can be configured and extended to understand any syntax that PostCSS can parse, including Sass, SugarSS, and Less.
The stylelint configuration is in the repository js-linter-configs, and available via NPM: