2501 lines
64 KiB
Markdown
Executable File
2501 lines
64 KiB
Markdown
Executable File
# Web Styleguide - Style guide to harmonize HTML, Javascript and CSS / Sass coding style
|
||
|
||
This document defines formatting and style rules for HTML, Javascript and CSS / SCSS. It aims at improving
|
||
collaboration, code quality, and enabling supporting infrastructure. It applies to raw, working files that use HTML,
|
||
Javascript and CSS, including Sass (SCSS) files.
|
||
|
||
If a group of developers start to use a style guide, errors become more obvious. If a certain parts of code are not
|
||
complying with the style guide it could be a style error but it could also be a bug. This makes it easier to review
|
||
code and to ensure errors are spotted more easily.
|
||
|
||
Tools are free to obfuscate, minify, and compile as long as the general code quality is maintained
|
||
and the raw files developers need to work with comply with the style guide.
|
||
|
||
You can also contribute to this style guide!
|
||
|
||
***
|
||
|
||
## General style rules
|
||
|
||
This section covers some general style rules that can be applied for HTML, Javascript and CSS / SCSS.
|
||
|
||
***
|
||
|
||
### File / Resource names
|
||
|
||
All file names in a web project should follow the same naming conventions. For readability purpose the minus (-) sign
|
||
is ideal for separating parts in a file name. Also it's a common separator in canonical URL and URL slugs
|
||
(i.e. `//example.com/blog/my-blog-entry` or `//s.example.com/images/big-black-background.jpg`). Therefore it's quite obvious
|
||
that the minus sign should be used to separate parts in a resource name.
|
||
|
||
Always start a file name with a letter and avoid numbers (except versions in the post-fix as outlined in the post-fix
|
||
note) where possible. There are special allowed cases where you need to start a filename with a special sign in order to
|
||
flag it for a special purpose (i.e. underscore for compass to ignore a certain file for direct css compilation).
|
||
|
||
All letters in a resource name should be lower case. This is a best practice as some operating systems support case
|
||
sensitive file names and we should not mix the cases to minimize confusion and possible sources for human errors.
|
||
|
||
There are cases where you will need to include some post- or pre-fixes or extensions (i.e. .min.js, .min.css) or
|
||
reeving which includes some pre-fixes (i.e. file hashes like 3fa89b.main.min.css). In those cases we recommend to use
|
||
dot's to separate the clear purpose of this additional meta-data in a filename.
|
||
|
||
**Not recommended**
|
||
```
|
||
MyScript.js
|
||
myCamelCaseName.css
|
||
i_love_underscores.html
|
||
1001-scripts.js
|
||
my-file-min.css
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
my-script.js
|
||
my-camel-case-name.css
|
||
i-love-underscores.html
|
||
thousand-and-one-scripts.js
|
||
my-file.min.css
|
||
```
|
||
|
||
***
|
||
|
||
### Protocol
|
||
|
||
Omit the protocol from embedded resources.
|
||
|
||
Omit the protocol portion (`http:`, `https:`) from URLs pointing to images and other media files, style sheets, and
|
||
scripts unless the respective files are not available over both protocols.
|
||
|
||
Omitting the protocol—which makes the URL relative—prevents mixed content issues and results in minor file size savings.
|
||
|
||
**Not recommended**
|
||
```
|
||
<script src="http://cdn.com/foundation.min.js"></script>
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<script src="//cdn.com/foundation.min.js"></script>
|
||
```
|
||
|
||
**Not recommended**
|
||
```
|
||
.example {
|
||
background: url(http://static.example.com/images/bg.jpg);
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.example {
|
||
background: url(//static.example.com/images/bg.jpg);
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Text indentation
|
||
|
||
Indent by 2 spaces at a time.
|
||
|
||
```
|
||
<ul>
|
||
<li>Fantastic</li>
|
||
<li>Great</li>
|
||
<li>
|
||
<a href="#">Test</a>
|
||
</li>
|
||
</ul>
|
||
```
|
||
|
||
```
|
||
@media screen and (min-width: 1100px) {
|
||
body {
|
||
font-size: 100%;
|
||
}
|
||
}
|
||
```
|
||
|
||
```
|
||
(function(){
|
||
var x = 10;
|
||
|
||
function y(a, b) {
|
||
return {
|
||
result: (a + b) * x
|
||
}
|
||
|
||
}
|
||
}());
|
||
```
|
||
|
||
***
|
||
|
||
### Comments
|
||
|
||
Comments are the only way others and **YOURSELF** know why a particular code was written and why it was written in the
|
||
way it was. It's crucial that you comment your code parts and specially code that is not trivial.
|
||
|
||
Self explaining code is a **MYTH**. There is no such thing as self explaining code. Also there is no such thing as too
|
||
many comments. There is only too little comments.
|
||
|
||
When you comment code don't comment what's coded, comment why it was coded this way and comment the thinking behind.
|
||
Also include links in your comments to open issues, specifications etc.
|
||
|
||
**Not recommended**
|
||
```
|
||
var offset = 0;
|
||
|
||
if(includeLabels) {
|
||
// Add offset of 20
|
||
offset = 20;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
var offset = 0;
|
||
|
||
if(includeLabels) {
|
||
// If the labels are included we need to have a minimum offset of 20 pixels
|
||
// We need to set it explicitly because of the following bug: http://somebrowservendor.com/issue-tracker/ISSUE-1
|
||
offset = 20;
|
||
}
|
||
```
|
||
|
||
Consider using annotations in your comments that help to structure commends and add meta information. For Javascript
|
||
use [JSDoc](http://usejsdoc.org/) or [YUIDoc](http://yui.github.io/yuidoc/). You can also use tools to generate
|
||
documentation from these comments. This is also a great way to encourage developers to write comments. Once comments
|
||
will be used to generate a living documentation they often start to spend more time for detailed comments.
|
||
|
||
***
|
||
|
||
### Code linting
|
||
|
||
For programming languages with less strictness it's important to enforce style rules and formatting guidelines.
|
||
Writing and following a style guide is a good practice but having an automated process that is enforcing it is even
|
||
better. Trust is good, control is better.
|
||
|
||
For Javascript we recommend to use JSLint / JSHint. In the repository for this styleguide you can also find a
|
||
[dotfile for jshint (.jshintrc)](.jshintrc). You can use this file with JSHint to enforce style
|
||
checking in your Javascript projects.
|
||
|
||
***
|
||
|
||
## HTML style rules
|
||
|
||
***
|
||
|
||
### Document type
|
||
|
||
HTML5 (HTML syntax) is preferred for all HTML documents: `<!DOCTYPE html>`.
|
||
|
||
(It’s recommended to use HTML, as text/html. Do not use XHTML. XHTML, as application/xhtml+xml,
|
||
lacks both browser and infrastructure support and offers less room for optimization than HTML.)
|
||
|
||
Although fine with HTML, do not close void elements, i.e. write `<br>`, not `<br />`.
|
||
|
||
***
|
||
|
||
### HTML validity
|
||
|
||
Use valid HTML code unless that is not possible due to otherwise unattainable performance goals regarding file size.
|
||
|
||
Use tools such as the W3C HTML validator to test.
|
||
|
||
Using valid HTML is a measurable baseline quality attribute that contributes to learning about technical requirements
|
||
and constraints, and that ensures proper HTML usage.
|
||
|
||
**Not recommended**
|
||
```
|
||
<title>Test</title>
|
||
<article>This is only a test.
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<!DOCTYPE html>
|
||
<meta charset="utf-8">
|
||
<title>Test</title>
|
||
<article>This is only a test.</article>
|
||
```
|
||
|
||
***
|
||
|
||
### Optional Tags
|
||
|
||
The HTML5 specification defines what tags can be omitted in the HTML markup. For readability purpose the raw source
|
||
file should **NOT** omit optional tags. Omitting optional tags can lead to readability and scannability issues, and
|
||
therefore should not be used in the raw source files.
|
||
|
||
Omitting tags can lead to significant page size reductions specially on large scale sites. For this purpose you should
|
||
consider an HTML minification post processing of your raw files for distribution purpose.
|
||
|
||
***
|
||
|
||
### Script loading
|
||
|
||
For performance reasons it's important to load scripts asynchronously. A script loaded in the `<head>` like this
|
||
`<script src="main.js"></script>` will block the whole DOM parsing until the script has fully loaded and executed. This
|
||
will delay the page to be displayed until the script has fully loaded. With larger scripts this can have a big impact
|
||
on user experience.
|
||
|
||
Asynchronous script loading helps to minimize this performance impact. If browser support is only concerned about IE10+
|
||
the HTML5 async attribute on scripts should be used. This will prevent DOM parser blocking and you can even place your
|
||
script element into the `<head>` element.
|
||
|
||
If you need to support older browsers it's common practice to use script loaders that will make use of dynamic script
|
||
injection. You should consider [yepnope](http://yepnopejs.com/) or [labjs](http://labjs.com/). The problem with injected
|
||
scripts though is that [they will not start loading until CSS Object Model is ready](https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/)
|
||
(shortly after the CSS from the head is loaded). This can also load to delay of your behavior added by these javascript
|
||
which can again affect the user experience.
|
||
|
||
As a result of the above described behaviors you should always consider the following best practice if you need to
|
||
support old browsers (IE9-).
|
||
|
||
Add your script element just before the body close tag and add them with a async attribute. This will not load the
|
||
scripts asynchronously on old browsers but they will only block the DOM parser just before the body close which is not
|
||
affecting the user experience too much. On modern browsers this will delay the script load until the DOM parser
|
||
discovers the script element at the end of the body, but they will then asynchronously load the script and don't wait
|
||
for CSSOM to complete before loading (execution will still happen after CSSOM).
|
||
|
||
**Recommended for modern and old browsers**
|
||
```
|
||
<html>
|
||
<head>
|
||
<link rel="stylesheet" href="main.css">
|
||
</head>
|
||
<body>
|
||
<!-- body goes here -->
|
||
|
||
<script src="main.js" async></script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
**Recommended for only modern browsers**
|
||
```
|
||
<html>
|
||
<head>
|
||
<link rel="stylesheet" href="main.css">
|
||
<script src="main.js" async></script>
|
||
</head>
|
||
<body>
|
||
<!-- body goes here -->
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
***
|
||
|
||
### Semantics
|
||
|
||
Use elements (sometimes incorrectly called “tags”) for what they have been created for. For example, use heading
|
||
elements for headings, p elements for paragraphs, a elements for anchors, etc.
|
||
|
||
Using HTML according to its purpose is important for accessibility, reuse, and code efficiency reasons.
|
||
|
||
The following bad / good example should outline some of the major important semantic HTML cases:
|
||
|
||
**Not recommended**
|
||
```
|
||
<b>My page title</b>
|
||
<div class="top-navigation">
|
||
<div class="nav-item"><a href="#home">Home</a></div>
|
||
<div class="nav-item"><a href="#news">News</a></div>
|
||
<div class="nav-item"><a href="#about">About</a></div>
|
||
</div>
|
||
|
||
<div class="news-page">
|
||
<div class="page-section news">
|
||
<div class="title">All news articles</div>
|
||
<div class="news-article">
|
||
<h2>Bad article</h2>
|
||
<div class="intro">Introduction sub-title</div>
|
||
<div class="content">This is a very bad example for HTML semantics</div>
|
||
<div class="article-side-notes">I think I'm more on the side and should not receive the main credits</div>
|
||
<div class="article-foot-notes">
|
||
This article was created by David <div class="time">2014-01-01 00:00</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-footer">
|
||
Related sections: Events, Public holidays
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="page-footer">
|
||
Copyright 2014
|
||
</div>
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<!-- The page header should go into a header element -->
|
||
<header>
|
||
<!-- As this title belongs to the page structure it's a heading and h1 should be used -->
|
||
<h1>My page title</h1>
|
||
</header>
|
||
|
||
<!-- All navigation should go into a nav element -->
|
||
<nav class="top-navigation">
|
||
<!-- A listing of elements should always go to UL (OL for ordered listings) -->
|
||
<ul>
|
||
<li class="nav-item"><a href="#home">Home</a></li>
|
||
<li class="nav-item"><a href="#news">News</a></li>
|
||
<li class="nav-item"><a href="#about">About</a></li>
|
||
</ul>
|
||
</nav>
|
||
|
||
<!-- The main part of the page should go into a main element (also use role="main" for accessibility) -->
|
||
<main class="news-page" role="main">
|
||
<!-- A section of a page should go into a section element. Divide a page into sections with semantic elements. -->
|
||
<section class="page-section news">
|
||
<!-- A section header should go into a section element -->
|
||
<header>
|
||
<!-- As a page section belongs to the page structure heading elements should be used (in this case h2) -->
|
||
<h2 class="title">All news articles</h2>
|
||
</header>
|
||
|
||
<!-- If a section / module can be seen as an article (news article, blog entry, products teaser, any other
|
||
re-usable module / section that can occur multiple times on a page) a article element should be used -->
|
||
<article class="news-article">
|
||
<!-- An article can contain a header that contains the summary / introduction information of the article -->
|
||
<header>
|
||
<!-- As a article title does not belong to the overall page structure there should not be any heading tag! -->
|
||
<div class="article-title">Good article</div>
|
||
<!-- Small can optionally be used to reduce importance -->
|
||
<small class="intro">Introduction sub-title</small>
|
||
</header>
|
||
|
||
<!-- For the main content in a section or article there is no semantic element -->
|
||
<div class="content">
|
||
<p>This is a good example for HTML semantics</p>
|
||
</div>
|
||
<!-- For content that is represented as side note or less important information in a given context use aside -->
|
||
<aside class="article-side-notes">
|
||
<p>I think I'm more on the side and should not receive the main credits</p>
|
||
</aside>
|
||
<!-- Articles can also contain footers. If you have footnotes for an article place them into a footer element -->
|
||
<footer class="article-foot-notes">
|
||
<!-- The time element can be used to annotate a timestamp. Use the datetime attribute to specify ISO time
|
||
while the actual text in the time element can also be more human readable / relative -->
|
||
<p>This article was created by David <time datetime="2014-01-01 00:00" class="time">1 month ago</time></p>
|
||
</footer>
|
||
</article>
|
||
|
||
<!-- In a section, footnotes or similar information can also go into a footer element -->
|
||
<footer class="section-footer">
|
||
<p>Related sections: Events, Public holidays</p>
|
||
</footer>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Your page footer should go into a global footer element -->
|
||
<footer class="page-footer">
|
||
Copyright 2014
|
||
</footer>
|
||
|
||
```
|
||
|
||
***
|
||
|
||
### Multimedia fallback
|
||
|
||
For multimedia, such as images, videos, animated objects via canvas, make sure to offer alternative access. For images
|
||
that means use of meaningful alternative text (alt) and for video and audio transcripts and captions, if available.
|
||
|
||
Providing alternative contents is important for accessibility reasons: A blind user has few cues to tell what an
|
||
image is about without @alt, and other users may have no way of understanding what video or audio contents are about
|
||
either.
|
||
|
||
(For images whose alt attributes would introduce redundancy, and for images whose purpose is purely decorative which
|
||
you cannot immediately use CSS for, use no alternative text, as in alt="".)
|
||
|
||
**Not recommended**
|
||
```
|
||
<img src="luke-skywalker.jpg">
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<img src="luke-skywalker.jpg" alt="Luke skywalker riding an alien horse">
|
||
```
|
||
|
||
When writing alt tags always try to describe the image as if you'd need to describe what's on the image to somebody
|
||
over the phone or who can't see the real picture.
|
||
|
||
**Not recommended**
|
||
```
|
||
<img src="huge-spaceship-approaching-earth.jpg" alt="Header image">
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<img src="huge-spaceship-approaching-earth.jpg" alt="A huge spaceship that is approaching the earth">
|
||
```
|
||
|
||
***
|
||
|
||
### Separation of Concerns
|
||
|
||
It's very important that you understand the different concerns in web and that you know how to and why to separate them.
|
||
In the web we have information (html markup), appearance (css) and behavior (Javascript) and we need to separate them as
|
||
far as possible in order to keep a maintainable and clean code.
|
||
|
||
Strictly keep structure (markup), presentation (styling), and behavior (scripting) apart, and try to keep the
|
||
interaction between the three to an absolute minimum.
|
||
|
||
That is, make sure documents and templates contain only HTML and HTML that is solely serving structural purposes.
|
||
Move everything presentational into style sheets, and everything behavioral into scripts.
|
||
|
||
In addition, keep the contact area as small as possible by linking as few style sheets and scripts as possible from
|
||
documents and templates.
|
||
|
||
Clean separation of concerns implies the following things:
|
||
|
||
1. Don't use more than one or two stylesheets (i.e. main.css, vendor.css)
|
||
1. Don't use more than one or two scripts (use concatination)
|
||
1. Don't use inline styles (`<style>.no-good {}</style>`)
|
||
1. Don't use element style attributes (`<hr style="border-top: 5px solid black">`)
|
||
1. Don't use inline scripts (`<script>alert('no good')</script>`)
|
||
1. Don't use presentational elements (i.e. `<b>`, `<u>`, `<center>`, `<font>`, `<b>`
|
||
1. Don't use presentational class names (i.e. red, left, center)
|
||
|
||
**Not recommended**
|
||
```
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<link rel="stylesheet" href="base.css">
|
||
<link rel="stylesheet" href="grid.css">
|
||
<link rel="stylesheet" href="type.css">
|
||
<link rel="stylesheet" href="modules/teaser.css">
|
||
</head>
|
||
<body>
|
||
<h1 style="font-size: 3rem"></h1>
|
||
<b>I'm a subtitle and I'm bold!</b>
|
||
<center>Dare you center me!</center>
|
||
<script>
|
||
alert('Just dont...');
|
||
</script>
|
||
<div class="red">I'm important!</div>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<!-- Concatinate your style sheets into a single one -->
|
||
<link rel="stylesheet" href="main.css">
|
||
</head>
|
||
<body>
|
||
<!-- Don't use style attributes but assign sensible classes and apply styles in the stylesheet -->
|
||
<h1 class="title"></h1>
|
||
<!-- Don't use presentational elements and assign sensible classes -->
|
||
<div class="sub-title">I'm a subtitle and I'm bold!</div>
|
||
<!-- Maybe your comments get centered in your presentation but that decision is up to the stylesheet -->
|
||
<span class="comment">Dare you center me!</span>
|
||
<!-- You wanted to make it red because it's important so then also name the class important and decide in the stylesheet
|
||
what you want to do with it -->
|
||
<div class="important">I'm important!</div>
|
||
|
||
<!-- Put all your scripts into files and concatinate them into a single one -->
|
||
<script async src="main.js"></script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
***
|
||
|
||
### HTML is content only
|
||
|
||
Don't pollute your HTML markup with non-content information. There is a tendency to solve design problems at
|
||
the information's cost. The HTML markup should only contain content relevant information and design problems should
|
||
never be solved within the markup.
|
||
|
||
The only purpose of HTML markup is to represent content information.
|
||
|
||
- Don't introduce a specific HTML structure just to solve some visual design problems
|
||
- Don't use `<img>` elements for visual design elements
|
||
|
||
The following examples show two common things that are done wrong when it comes to solving design problems.
|
||
|
||
**Not recommended**
|
||
```
|
||
<!-- We should not introduce an additional element just to solve a design problem -->
|
||
<span class="text-box">
|
||
<span class="square"></span>
|
||
See the square next to me?
|
||
</span>
|
||
|
||
```
|
||
```
|
||
.text-box > .square {
|
||
display: inline-block;
|
||
width: 1rem;
|
||
height: 1rem;
|
||
background-color: red;
|
||
}
|
||
```
|
||
|
||
|
||
**Recommended**
|
||
```
|
||
<!-- That's clean markup! -->
|
||
<span class="text-box">
|
||
See the square next to me?
|
||
</span>
|
||
|
||
```
|
||
```
|
||
// We use a :before pseudo element to solve the design problem of placing a colored square in front of the text content
|
||
.text-box:before {
|
||
content: "";
|
||
display: inline-block;
|
||
width: 1rem;
|
||
height: 1rem;
|
||
background-color: red;
|
||
}
|
||
```
|
||
|
||
The only reason for images and svg graphics to be included in the markup is because they represent content relevant
|
||
information.
|
||
|
||
**Not recommended**
|
||
```
|
||
<!-- Content images should never be used for design elements! -->
|
||
<span class="text-box">
|
||
<img src="square.svg" alt="Square" />
|
||
See the square next to me?
|
||
</span>
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<!-- That's clean markup! -->
|
||
<span class="text-box">
|
||
See the square next to me?
|
||
</span>
|
||
|
||
```
|
||
```
|
||
// We use a :before pseudo element with a background image to solve the problem
|
||
.text-box:before {
|
||
content: "";
|
||
display: inline-block;
|
||
width: 1rem;
|
||
height: 1rem;
|
||
background: url(square.svg) no-repeat;
|
||
background-size: 100%;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Type attributes
|
||
|
||
Omit type attributes for style sheets and scripts. Do not use type attributes for style sheets (unless not using CSS)
|
||
and scripts (unless not using JavaScript). Specifying type attributes in these contexts is not necessary as
|
||
HTML5 implies text/css and text/javascript as defaults. This can be safely done even for older browsers.
|
||
|
||
**Not recommended**
|
||
```
|
||
<link rel="stylesheet" href="main.css" type="text/css">
|
||
<script src="main.js" type="text/javascript"></script>
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<link rel="stylesheet" href="main.css">
|
||
<script src="main.js"></script>
|
||
```
|
||
|
||
***
|
||
|
||
### General Accessibility
|
||
|
||
If you use proper HTML5 semantics a lot of accessibility issues are already solved. ARIA is using some default roles
|
||
for most of the semantic elements which, if used correctly, solves a lot of the issues already. If you use `nav`,
|
||
`aside`, `main`, `footer` etc. ARIA will use some related default roles. For more details you can reference the
|
||
[ARIA specification](http://rawgit.com/w3c/aria-in-html/master/index.html#recommendations-table) recommendation table
|
||
which contains the defaults for the HTML semantic elements.
|
||
|
||
Additional roles can be used to give more accessibility context (i.e. `role="tab"`).
|
||
|
||
***
|
||
|
||
### Tab Index for Accessibility
|
||
|
||
Check your document for tab order and assign tabindex values in order to change the tab flow based on priority. You
|
||
can disable the tab index of an element by setting `tabindex="-1"` on any element.
|
||
|
||
If you add functionality to a element that is not focusable by default, you should always add a `tabindex` in order to
|
||
make the element focusable. This will also enable the CSS pseudo selector `:focus`. Choose an appropriate index value
|
||
for `tabindex` or use `tabindex="0"` to group elements into one tab order level and enforce ordering in natural reading
|
||
order.
|
||
|
||
***
|
||
|
||
### Microdata for SEO and Accessibility
|
||
|
||
If the SEO relevance and / or accessibility environment is given then you should consider to use microdata where
|
||
possible. Microdata is a way to annotate your data in your markup that follows some specific semantics.
|
||
|
||
Google, Microsoft and Yahoo! have more or less agreed on how to use this additional data and using it correctly has
|
||
great influence on your searches.
|
||
|
||
You can visit [schema.org](http://schema.org/) for more details.
|
||
|
||
Simple example of a movie on a web page:
|
||
|
||
**Without microdata**
|
||
```
|
||
<div>
|
||
<h1>Avatar</h1>
|
||
<span>Director: James Cameron (born August 16, 1954)</span>
|
||
<span>Science fiction</span>
|
||
<a href="../movies/avatar-theatrical-trailer.html">Trailer</a>
|
||
</div>
|
||
```
|
||
|
||
**With microdata**
|
||
```
|
||
<div itemscope itemtype ="http://schema.org/Movie">
|
||
<h1 itemprop="name">Avatar</h1>
|
||
<div itemprop="director" itemscope itemtype="http://schema.org/Person">
|
||
Director: <span itemprop="name">James Cameron</span> (born <span itemprop="birthDate">August 16, 1954)</span>
|
||
</div>
|
||
<span itemprop="genre">Science fiction</span>
|
||
<a href="../movies/avatar-theatrical-trailer.html" itemprop="trailer">Trailer</a>
|
||
</div>
|
||
```
|
||
|
||
***
|
||
|
||
### IDs for anchors
|
||
|
||
It's generally a good practice to give all headings on a page a ID. With these ID's on headings you can use the
|
||
browsers default behavior and include the ID names as hash tags in the URL. By default this causes the browser to scroll
|
||
to the position this element.
|
||
|
||
If you'd enter the URL `http://your-site.com/about#best-practices` in your browser then the browser would scroll down
|
||
so that the H3 below would be scrolled into the view.
|
||
|
||
```
|
||
<h3 id="best-practices">Best practices</h3>
|
||
```
|
||
|
||
***
|
||
|
||
### General formatting
|
||
|
||
Use a new line for every block, list, or table element, and indent every such child element.
|
||
Independent of the styling of an element (as CSS allows elements to assume a different role per display property),
|
||
put every block, list, or table element on a new line.
|
||
|
||
Also, indent them if they are child elements of a block, list, or table element.
|
||
|
||
(If you run into issues around whitespace between list items it’s acceptable to put all li elements in one line.
|
||
A linter is encouraged to throw a warning instead of an error.)
|
||
|
||
**Recommended**
|
||
```
|
||
<blockquote>
|
||
<p><em>Space</em>, the final frontier.</p>
|
||
</blockquote>
|
||
|
||
<ul>
|
||
<li>Moe</li>
|
||
<li>Larry</li>
|
||
<li>Curly</li>
|
||
</ul>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th scope="col">Income</th>
|
||
<th scope="col">Taxes</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>$ 5.00</td>
|
||
<td>$ 4.50</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
```
|
||
|
||
***
|
||
|
||
### HTML quotation marks
|
||
|
||
When quoting attributes values, use double quotation marks. Use double ("") rather than single quotation marks ('')
|
||
around attribute values.
|
||
|
||
**Not recommended**
|
||
```
|
||
<div class='news-article'></div>
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
<div class="news-article"></div>
|
||
```
|
||
|
||
***
|
||
|
||
## Javascript style guide
|
||
|
||
***
|
||
|
||
### Global namespace pollution and IIFE
|
||
|
||
Always wrap your code into a IIFE (Immediately-Invoked Function Expression) in order to create an isolated closure
|
||
scope. This prevents you from polluting the global namespace.
|
||
|
||
IIFE can also secure your code from modifications that happened in the global namespace (i.e. 3rd party libraries,
|
||
window reference, overridden undefined keyword etc.)
|
||
|
||
**Not recommended**
|
||
```
|
||
var x = 10,
|
||
y = 100;
|
||
|
||
// Declaring variables in the global scope is resulting in global scope pollution. All variables declared like this
|
||
// will be stored in the window object. This is very unclean and needs to be avoided.
|
||
console.log(window.x + ' ' + window.y);
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
// We declare a IIFE and pass parameters into the function that we will use from the global space
|
||
(function(log, w, undefined){
|
||
'use strict';
|
||
|
||
var x = 10,
|
||
y = 100;
|
||
|
||
// Will output 'true true'
|
||
log((w.x === undefined) + ' ' + (w.y === undefined));
|
||
|
||
}(window.console.log, window));
|
||
```
|
||
|
||
***
|
||
|
||
### IIFE (Immediately-Executed Function Expression)
|
||
|
||
Use IIFE whenever you want to create a new closure scope. This can be used to create privacy and to keep memory clean.
|
||
|
||
Every javascript file should start with an IIFE.
|
||
|
||
The IIFE should be written so you're keeping the execution brackets inside of the surrounding brackets. Although the
|
||
writing the executing brackets outside of the surrounding brackets is valid the second example should be used as this
|
||
sets clear boundaries for the IIFE as the surrounding brackets isolate the whole IIFE.
|
||
|
||
**Not recommended**
|
||
```
|
||
(function(){})();
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
(function(){}());
|
||
```
|
||
|
||
The following pattern should be used to format your IIFE:
|
||
|
||
```
|
||
(function(){
|
||
'use strict';
|
||
|
||
// Code goes here
|
||
|
||
}());
|
||
```
|
||
|
||
If you want to use global variables or variables form an outer IIFE you should pass them as parameters to your IIFE:
|
||
```
|
||
(function($, w, d){
|
||
'use strict';
|
||
|
||
$(function() {
|
||
w.alert(d.querySelectorAll('div').length);
|
||
});
|
||
}(jQuery, window, document));
|
||
```
|
||
|
||
***
|
||
|
||
### Strict mode
|
||
|
||
ECMAScript 5 strict mode can be enabled globally in your script or on function level. It enables more strict error
|
||
handling as well different javascript semantics. Strict mode also enforces a syntax that allows engines to optimize
|
||
the javascript better and strict more scripts can run faster than normal scripts.
|
||
|
||
Strict mode also blocks the usage of reserved words that possibly get introduced in the future.
|
||
|
||
You should always enforce strict mode in your scripts. Do so by applying it in your isolation IIFE. Don't apply it to
|
||
your whole script by include it as first statement in your script. This could possibly cause issues with 3rd party
|
||
libraries.
|
||
|
||
**Not recommended**
|
||
```
|
||
// Script starts here
|
||
'use strict';
|
||
|
||
(function(){
|
||
|
||
// Your code starts here
|
||
|
||
}());
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
(function(){
|
||
'use strict';
|
||
|
||
// Your code starts here
|
||
|
||
}());
|
||
```
|
||
|
||
***
|
||
|
||
### Variable declarations
|
||
|
||
Always use `var` to declare your variables. When you fail to specify var, the variable gets placed in the global
|
||
context, potentially clobbering existing values. Also, if there's no declaration, it's hard to tell in what scope a
|
||
variable lives (e.g., it could be in the Document or Window just as easily as in the local scope).
|
||
So always declare with var.
|
||
|
||
Using strict mode can help to identify issues where you might mistyped a variable name resulting in a ReferenceError.
|
||
|
||
**Not recommended**
|
||
```
|
||
x = 10;
|
||
y = 100;
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
var x = 10,
|
||
y = 100;
|
||
```
|
||
|
||
***
|
||
|
||
### Understand Javascript scope and hoisting
|
||
|
||
In Javascript variable and function declarations will be hoisted before execution. Javascript only knows function scope
|
||
and there is no block scope as you know it from other programming languages. This means that if you declare a variable
|
||
inside a if statement or for loop this variable is declared for the whole function scope and not only locally in the
|
||
block statement.
|
||
|
||
To illustrate this check the following example that will show how a javascript interpreter is hoisting the declarations
|
||
in a function scope:
|
||
|
||
**Raw function**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var a = 10;
|
||
|
||
for(var i = 0; i < a; i++) {
|
||
var b = i * i;
|
||
log(b);
|
||
}
|
||
|
||
if(a === 10) {
|
||
var f = function() {
|
||
log(a);
|
||
};
|
||
f();
|
||
}
|
||
|
||
function x() {
|
||
log('Mr. X!');
|
||
}
|
||
x();
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
**Hoisted by Javscript engine**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
// All variables used in the closure will be hoisted to the top of the function
|
||
var a,
|
||
i,
|
||
b,
|
||
f;
|
||
// All functions in the closure will be hoisted to the top
|
||
function x() {
|
||
log('Mr. X!');
|
||
}
|
||
|
||
a = 10;
|
||
|
||
for(i = 0; i < a; i++) {
|
||
b = i * i;
|
||
log(b);
|
||
}
|
||
|
||
if(a === 10) {
|
||
// Function assignments will only result in hoisted variables but the function body will not be hoisted
|
||
// Only by using a real function declaration the whole function will be hoisted with its body
|
||
f = function() {
|
||
log(a);
|
||
};
|
||
f();
|
||
}
|
||
|
||
x();
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
Considering now the hoisting above you can now see that you could also run the following code without any exceptions:
|
||
|
||
**Valid code**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var a = 10;
|
||
|
||
i = 5;
|
||
|
||
x();
|
||
|
||
for(var i; i < a; i++) {
|
||
log(b);
|
||
var b = i * i;
|
||
}
|
||
|
||
if(a === 10) {
|
||
f = function() {
|
||
log(a);
|
||
};
|
||
f();
|
||
|
||
var f;
|
||
}
|
||
|
||
function x() {
|
||
log('Mr. X!');
|
||
}
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
As you can see this looks very confusing and misunderstanding hoisting can lead to unexpected results. To minimize the
|
||
risk of errors and bugs that resulted from misunderstanding hoisting your should follow the style rule of hoisted
|
||
declarations in the next section.
|
||
|
||
***
|
||
|
||
### Use hoisted declarations
|
||
|
||
To minimize risk of misunderstanding and misinterpreting results from hoisted variable and function declarations (see
|
||
previous section) you should always try to hoist your variable and function declarations manually. This means that
|
||
you should declare all your variables that you're using in a function as a fist statement in the function.
|
||
|
||
Use only one `var` keyword and comma separate multiple declarations.
|
||
|
||
**Not recommended**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var a = 10;
|
||
var b = 10;
|
||
|
||
for(var i = 0; i < 10; i++) {
|
||
var c = a * b * i;
|
||
}
|
||
|
||
function f() {
|
||
|
||
}
|
||
|
||
var d = 100;
|
||
var x = function() {
|
||
return d * d;
|
||
};
|
||
log(x());
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var a = 10,
|
||
b = 10,
|
||
i,
|
||
c,
|
||
d,
|
||
x;
|
||
|
||
function f() {
|
||
|
||
}
|
||
|
||
for(i = 0; i < 10; i++) {
|
||
c = a * b * i;
|
||
}
|
||
|
||
|
||
|
||
d = 100;
|
||
x = function() {
|
||
return d * d;
|
||
};
|
||
log(x());
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
Being pragmatic you should directly initialize your variables during hoisted declaration.
|
||
|
||
**Not recommended**
|
||
```
|
||
var a,
|
||
b,
|
||
c;
|
||
|
||
a = 10;
|
||
b = 10;
|
||
c = 100;
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
var a = 10,
|
||
b = 10,
|
||
c = 100;
|
||
```
|
||
|
||
***
|
||
|
||
### Always use strict equal
|
||
|
||
Always use `===` explicit comparison operators and avoid the hassle you can go through by debugging issues resulted
|
||
from the very much overcomplicated javascript type coercion.
|
||
|
||
If you're using `===` operators both operands need to be from the same type in order to be valid and there will no
|
||
type coercion be performed.
|
||
|
||
If you'd like to get more information on type coercion you should read
|
||
[this article by Dmitry Soshnikov](http://dmitrysoshnikov.com/notes/note-2-ecmascript-equality-operators/).
|
||
|
||
By using only `==` you're telling javascript to use type coercion where needed which can be very complicated to trace
|
||
down. A few examples can be seen below that should give you a indication how strange type coercion can feel:
|
||
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
log('0' == 0); // true
|
||
log('' == false); // true
|
||
log('1' == true); // true
|
||
log(null == undefined); // true
|
||
|
||
var x = {
|
||
valueOf: function() {
|
||
return 'X';
|
||
}
|
||
};
|
||
|
||
log(x == 'X');
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
***
|
||
|
||
### Use truthy / falsy checks wisely
|
||
|
||
By only putting one variable or expression into a if statement you're creating a truthy / falsy check. The expression
|
||
`if(a == true)` is not the same as `if(a)`. The later expression is creating a special check which is called truthy /
|
||
falsy check. This check performs some special operations in order to evaluate to true or false. The following
|
||
expressions are falsy in javascript `false`, `0`, `undefined`, `null`, `NaN`, `''` (empty string).
|
||
|
||
Truthy / falsy checks are very helpful as they allow you to quickly react on a group of conditions that you'd like to
|
||
take care of but you need to be sure about what you actually want to do.
|
||
|
||
The following example shows how truthy / falsy checks work:
|
||
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
function logTruthyFalsy(expr) {
|
||
if(expr) {
|
||
log('truthy');
|
||
} else {
|
||
log('falsy');
|
||
}
|
||
}
|
||
|
||
logTruthyFalsy(true); // truthy
|
||
logTruthyFalsy(1); // truthy
|
||
logTruthyFalsy({}); // truthy
|
||
logTruthyFalsy([]); // truthy
|
||
logTruthyFalsy('0'); // truthy
|
||
|
||
logTruthyFalsy(false); // falsy
|
||
logTruthyFalsy(0); // falsy
|
||
logTruthyFalsy(undefined); // falsy
|
||
logTruthyFalsy(null); // falsy
|
||
logTruthyFalsy(NaN); // falsy
|
||
logTruthyFalsy(''); // falsy
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
***
|
||
|
||
### Logical operators for variable assignments
|
||
|
||
The logical operators `||` and `&&` can also be used to return non-boolean values. If used with non booleans the
|
||
operands will evaluate each expression from left to right and performs a falsy check. Depending on the operation, one
|
||
of the expressions will be returned. This can be very helpful for variable assignments and should be considered in
|
||
order to simplify your code.
|
||
|
||
**Not recommended**
|
||
```
|
||
if(!x) {
|
||
if(!y) {
|
||
x = 1;
|
||
} else {
|
||
x = y;
|
||
}
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
x = x || y || 1;
|
||
```
|
||
|
||
This shorthand is often used to validated function parameters. The following example illustrates one usage example:
|
||
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
function multiply(a, b) {
|
||
a = a || 1;
|
||
b = b || 1;
|
||
|
||
log('Result ' + a * b);
|
||
}
|
||
|
||
multiply(); // Result 1
|
||
multiply(10); // Result 10
|
||
multiply(3, NaN); // Result 3
|
||
multiply(9, 5); // Result 45
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
***
|
||
|
||
### Semicolons
|
||
|
||
Always use semicolons. Relying on implicit insertion can cause subtle, hard to debug problems. Don't do it.
|
||
You're better than that. There are a couple places where missing semicolons are particularly dangerous:
|
||
|
||
```
|
||
// 1.
|
||
MyClass.prototype.myMethod = function() {
|
||
return 42;
|
||
} // No semicolon here.
|
||
|
||
(function() {
|
||
// Some initialization code wrapped in a function to create a scope for locals.
|
||
})();
|
||
|
||
|
||
var x = {
|
||
'i': 1,
|
||
'j': 2
|
||
} // No semicolon here.
|
||
|
||
// 2. Trying to do one thing on Internet Explorer and another on Firefox.
|
||
// I know you'd never write code like this, but throw me a bone.
|
||
[ffVersion, ieVersion][isIE]();
|
||
|
||
|
||
var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No semicolon here.
|
||
|
||
// 3. conditional execution a la bash
|
||
-1 == resultOfOperation() || die();
|
||
```
|
||
|
||
**So what happens?**
|
||
|
||
1. JavaScript error - first the function returning 42 is called with the second function as a parameter, then
|
||
the number 42 is "called" resulting in an error.
|
||
1. You will most likely get a 'no such property in undefined' error at runtime as it tries to
|
||
call `x[ffVersion, ieVersion][isIE]()`.
|
||
1. `die` is always called since the array minus 1 is `NaN` which is never equal to anything (not even if
|
||
`resultOfOperation()` returns `NaN`) and `THINGS_TO_EAT` gets assigned the result of `die()`.
|
||
|
||
**Why?**
|
||
|
||
JavaScript requires statements to end with a semicolon, except when it thinks it can safely infer their existence.
|
||
In each of these examples, a function declaration or object or array literal is used inside a statement. The closing
|
||
brackets are not enough to signal the end of the statement. Javascript never ends a statement if the next token is an
|
||
infix or bracket operator.
|
||
|
||
This has really surprised people, so make sure your assignments end with semicolons.
|
||
|
||
**Clarification: Semicolons and functions**
|
||
|
||
Semicolons should be included at the end of function expressions, but not at the end of function declarations.
|
||
The distinction is best illustrated with an example:
|
||
|
||
```
|
||
var foo = function() {
|
||
return true;
|
||
}; // semicolon here.
|
||
|
||
function foo() {
|
||
return true;
|
||
} // no semicolon here.
|
||
```
|
||
|
||
***
|
||
|
||
### Nested functions
|
||
|
||
Nested functions can be very useful, for example in the creation of continuations and for the task of hiding helper
|
||
functions. Feel free to use them.
|
||
|
||
***
|
||
|
||
### Function declaration within blocks
|
||
|
||
Do not declare functions in blocks. This is not valid in ECMAScript 5 strict mode. Functions should be declared on
|
||
top level. Don't hesitate to use variables initialized with function expressions inside of blocks though:
|
||
|
||
**Not recommended**
|
||
```
|
||
if (x) {
|
||
function foo() {}
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
if (x) {
|
||
var foo = function() {};
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Exceptions
|
||
|
||
You basically can't avoid exceptions if you're doing something non-trivial (using an application development framework,
|
||
etc.).
|
||
|
||
Without custom exceptions, returning error information from a function that also returns a value can be tricky, not to
|
||
mention inelegant. Bad solutions include passing in a reference type to hold error information or always returning
|
||
Objects with a potential error member. These basically amount to a primitive exception handling hack.
|
||
Feel free to use custom exceptions when appropriate.
|
||
|
||
In complex environments you should consider throwing objects rather than just strings (default throws).
|
||
|
||
```
|
||
if(name === undefined) {
|
||
throw {
|
||
name: 'System Error',
|
||
message: 'A name should always be specified!'
|
||
}
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Standard features
|
||
|
||
Always preferred over non-standards features. For maximum portability and compatibility, always prefer standards
|
||
features over non-standards features (e.g., `string.charAt(3)` over `string[3]` and element access with DOM functions
|
||
instead of using an application-specific shorthand).
|
||
|
||
***
|
||
|
||
### Simple prototypical inheritance
|
||
|
||
If you need inheritance of your objects in Javascript follow a simple pattern to create inheritance. If you know that
|
||
you'll end up with complex object inheritance consider a inheritance library like
|
||
[Proto.js by Axel Rauschmayer](https://github.com/rauschma/proto-js).
|
||
|
||
For simple cases use like the bellow.
|
||
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
// Constructor function
|
||
function Apple(name) {
|
||
this.name = name;
|
||
}
|
||
// Defining a method of apple
|
||
Apple.prototype.eat = function() {
|
||
log('Eating ' + this.name);
|
||
};
|
||
|
||
// Constructor function
|
||
function GrannySmithApple() {
|
||
// Invoking parent constructor
|
||
Apple.prototype.constructor.call(this, 'Granny Smith');
|
||
}
|
||
// Set parent prototype while creating a copy with Object.create
|
||
GrannySmithApple.prototype = Object.create(Apple.prototype);
|
||
// Set constructor to the sub type, otherwise points to Apple
|
||
GrannySmithApple.prototype.constructor = GrannySmithApple;
|
||
|
||
// Calling a super method
|
||
GrannySmithApple.prototype.eat = function() {
|
||
// Be sure to apply it onto our current object with call(this)
|
||
Apple.prototype.eat.call(this);
|
||
|
||
log('Poor Grany Smith');
|
||
};
|
||
|
||
// Instantiation
|
||
var apple = new Apple('Test Apple');
|
||
var grannyApple = new GrannySmithApple();
|
||
|
||
log(apple.name); // Test Apple
|
||
log(grannyApple.name); // Granny Smith
|
||
|
||
// Instance checks
|
||
log(apple instanceof Apple); // true
|
||
log(apple instanceof GrannySmithApple); // false
|
||
|
||
log(grannyApple instanceof Apple); // true
|
||
log(grannyApple instanceof GrannySmithApple); // true
|
||
|
||
// Calling method that calls super method
|
||
grannyApple.eat(); // Eating Granny Smith\nPoor Grany Smith
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
***
|
||
|
||
### Use Closures
|
||
|
||
The ability to create closures is perhaps the most useful and often overlooked feature of JS.
|
||
Here is [a good description of how closures work](http://jibbering.com/faq/faq_notes/closures.html).
|
||
|
||
***
|
||
|
||
### Don't create functions in loops
|
||
|
||
It's generally a potential source for bugs if you write functions that create a closure inside of simple loops. The
|
||
following example illustrates a common pitfall.
|
||
|
||
**Not recommended**
|
||
```
|
||
(function(log, w){
|
||
'use strict';
|
||
|
||
// numbers and i is defined in the current function closure
|
||
var numbers = [1, 2, 3],
|
||
i;
|
||
|
||
for(i = 0; i < numbers.length; i++) {
|
||
w.setTimeout(function() {
|
||
// At the moment when this gets executed the i variable, coming from the outer function scope
|
||
// is set to 3 and the current program is alerting the message 3 times
|
||
// 'Index 3 with number undefined
|
||
// If you understand closures in javascript you know how to deal with those cases
|
||
// It's best to just avoid functions / new closures in loops as this prevents those issues
|
||
|
||
w.alert('Index ' + i + ' with number ' + numbers[i]);
|
||
}, 0);
|
||
}
|
||
|
||
}(window.console.log, window));
|
||
```
|
||
|
||
The following variation of the above example solves our problem / bug but still violates our policy to not create
|
||
functions / closures inside of loops.
|
||
|
||
**Not recommended**
|
||
```
|
||
(function(log, w){
|
||
'use strict';
|
||
|
||
// numbers and i is defined in the current function closure
|
||
var numbers = [1, 2, 3],
|
||
i;
|
||
|
||
for(i = 0; i < numbers.length; i++) {
|
||
// Creating a new closure scope with an IIFE solves the problem
|
||
// The delayed function will use index and number which are
|
||
// in their own closure scope (one closure per loop iteration).
|
||
// ---
|
||
// Still this is not recommended as we violate our rule to not
|
||
// create functions within loops and we are creating two!
|
||
|
||
(function(index, number){
|
||
w.setTimeout(function() {
|
||
// Will output as expected 0 > 1, 1 > 2, 2 > 3
|
||
w.alert('Index ' + index + ' with number ' + number);
|
||
}, 0);
|
||
}(i, numbers[i]));
|
||
}
|
||
|
||
}(window.console.log, window));
|
||
```
|
||
|
||
The following variation solves our problem / bug and we also comply with our style guide. However, this seems to be
|
||
heavily overcomplicated and we should look for a better / easier way.
|
||
|
||
**Partially recommended**
|
||
```
|
||
(function(log, w){
|
||
'use strict';
|
||
|
||
// numbers and i is defined in the current function closure
|
||
var numbers = [1, 2, 3],
|
||
i;
|
||
|
||
// Create a function outside of the loop that will accept arguments to create a
|
||
// function closure scope. This function will return a function that executes in this
|
||
// closure parent scope.
|
||
function alertIndexWithNumber(index, number) {
|
||
return function() {
|
||
w.alert('Index ' + index + ' with number ' + number);
|
||
};
|
||
}
|
||
|
||
// First parameter is a function call that returns a function.
|
||
// ---
|
||
// This solves our problem and we don't create a function inside our loop
|
||
for(i = 0; i < numbers.length; i++) {
|
||
w.setTimeout(alertIndexWithNumber(i, numbers[i]), 0);
|
||
}
|
||
|
||
}(window.console.log, window));
|
||
```
|
||
|
||
By using a functional approach for our loop we solve the problem immediately as we create a new closure with every loop.
|
||
Functional style is recommended and will also lead to more natural and expected results.
|
||
|
||
**Recommended**
|
||
```
|
||
(function(log, w){
|
||
'use strict';
|
||
|
||
// numbers and i is defined in the current function closure
|
||
var numbers = [1, 2, 3],
|
||
i;
|
||
|
||
numbers.forEach(function(number, index) {
|
||
w.setTimeout(function() {
|
||
w.alert('Index ' + index + ' with number ' + number);
|
||
}, 0);
|
||
});
|
||
|
||
}(window.console.log, window));
|
||
```
|
||
|
||
***
|
||
|
||
### The (evil) eval function
|
||
|
||
`eval()` makes for confusing semantics and is dangerous to use if the string being eval()'d contains user input.
|
||
There's usually a better, clearer, and safer way to write your code, so its use is generally not permitted.
|
||
|
||
***
|
||
|
||
### The this keyword
|
||
|
||
Use the `this` keyword only in object constructors, methods, and in setting up closures. The semantics of this can be
|
||
tricky. At times it refers to the global object (in most places), the scope of the caller (in eval), a node in the DOM
|
||
tree (when attached using an event handler HTML attribute), a newly created object (in a constructor), or some other
|
||
object (if function was call()ed or apply()ed).
|
||
|
||
Because this is so easy to get wrong, limit its use to those places where it is required:
|
||
|
||
- in constructors
|
||
- in methods of objects (including in the creation of closures)
|
||
|
||
***
|
||
|
||
### Functional is preferred
|
||
|
||
Using functional style programming you can simplify your code and reduce maintenance cost by gaining easy re-usability,
|
||
proper isolation and less dependencies.
|
||
|
||
The following example compares two solutions for the same problem of summing up all number elements in an array. The
|
||
first example is a classical procedural approach while the second one makes use of functional style programming and the
|
||
ECMA Script 5.1 array functions.
|
||
|
||
Exception: In situations where performance is considered to be more important than maintainability then you might
|
||
consider the most performant solution over the most maintainable (i.e. using simple for loop over forEach)
|
||
|
||
**Not recommended**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var arr = [10, 3, 7, 9, 100, 20],
|
||
sum = 0,
|
||
i;
|
||
|
||
|
||
for(i = 0; i < arr.length; i++) {
|
||
sum += arr[i];
|
||
}
|
||
|
||
log('The sum of array ' + arr + ' is: ' + sum)
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var arr = [10, 3, 7, 9, 100, 20];
|
||
|
||
var sum = arr.reduce(function(prevValue, currentValue) {
|
||
return prevValue + currentValue;
|
||
}, 0);
|
||
|
||
log('The sum of array ' + arr + ' is: ' + sum);
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
An other example would be to filter an array for certain criteria so that we can create a new array that only contains
|
||
those elements that match the criteria.
|
||
|
||
**Not recommended**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var numbers = [11, 3, 7, 9, 100, 20, 14, 10],
|
||
numbersGreaterTen = [],
|
||
i;
|
||
|
||
|
||
for(i = 0; i < numbers.length; i++) {
|
||
if(numbers[i] > 10) {
|
||
numbersGreaterTen.push(numbers[i]);
|
||
}
|
||
}
|
||
|
||
log('From the list of numbers ' + numbers + ' only ' + numbersGreaterTen + ' are greater than ten');
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
var numbers = [11, 3, 7, 9, 100, 20, 14, 10];
|
||
|
||
var numbersGreaterTen = numbers.filter(function(element) {
|
||
return element > 10;
|
||
});
|
||
|
||
log('From the list of numbers ' + numbers + ' only ' + numbersGreaterTen + ' are greater than ten');
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
***
|
||
|
||
### Use ECMA Script 5
|
||
|
||
Use the syntactical sugar and functional style that was added with ECMA Script 5. It's simplifying your programming
|
||
style and makes your code more flexible and re-usable.
|
||
|
||
***
|
||
|
||
### Array and object property iteration
|
||
|
||
The ECMA5 way to iterate over an array is preferred. Use Array.forEach or Array.every if you would like to cancel the
|
||
iteration at a certain condition.
|
||
|
||
```
|
||
(function(log){
|
||
'use strict';
|
||
|
||
// Iterate over an array and break at a certain condition
|
||
[1, 2, 3, 4, 5].every(function(element, index, arr) {
|
||
log(element + ' at index ' + index + ' in array ' + arr);
|
||
|
||
if(index !== 5) {
|
||
return true;
|
||
}
|
||
});
|
||
|
||
// Defining a simple javascript object
|
||
var obj = {
|
||
a: 'A',
|
||
b: 'B',
|
||
'c-d-e': 'CDE'
|
||
};
|
||
|
||
// Iterating over the object keys
|
||
Object.keys(obj).forEach(function(element, index, arr) {
|
||
log('Key ' + element + ' has value ' + obj[element]);
|
||
});
|
||
|
||
}(window.console.log));
|
||
```
|
||
|
||
***
|
||
|
||
### Don't use switch
|
||
|
||
switch is a very error prone control statement in every programming language. Use if else if instead.
|
||
|
||
***
|
||
|
||
### Array and Object literals
|
||
|
||
Use Array and Object literals instead of Array and Object constructors. Array constructors are error-prone due to their
|
||
arguments.
|
||
|
||
**Not recommended**
|
||
```
|
||
// Length is 3.
|
||
var a1 = new Array(x1, x2, x3);
|
||
|
||
// Length is 2.
|
||
var a2 = new Array(x1, x2);
|
||
|
||
// If x1 is a number and it is a natural number the length will be x1.
|
||
// If x1 is a number but not a natural number this will throw an exception.
|
||
// Otherwise the array will have one element with x1 as its value.
|
||
var a3 = new Array(x1);
|
||
|
||
// Length is 0.
|
||
var a4 = new Array();
|
||
```
|
||
|
||
Because of this, if someone changes the code to pass 1 argument instead of 2 arguments, the array might not have the
|
||
expected length. To avoid these kinds of weird cases, always use the more readable array literal.
|
||
|
||
**Recommended**
|
||
```
|
||
var a = [x1, x2, x3];
|
||
var a2 = [x1, x2];
|
||
var a3 = [x1];
|
||
var a4 = [];
|
||
```
|
||
|
||
Object constructors don't have the same problems, but for readability and consistency object literals should be used.
|
||
|
||
**Not recommended**
|
||
```
|
||
var o = new Object();
|
||
|
||
var o2 = new Object();
|
||
o2.a = 0;
|
||
o2.b = 1;
|
||
o2.c = 2;
|
||
o2['strange key'] = 3;
|
||
```
|
||
|
||
Should be written as:
|
||
|
||
**Recommended**
|
||
```
|
||
var o = {};
|
||
|
||
var o2 = {
|
||
a: 0,
|
||
b: 1,
|
||
c: 2,
|
||
'strange key': 3
|
||
};
|
||
```
|
||
|
||
***
|
||
|
||
### Modifying prototypes of builtin objects
|
||
|
||
Modifying builtins like `Object.prototype` and `Array.prototype` are strictly forbidden. Modifying other builtins like
|
||
`Function.prototype` is less dangerous but still leads to hard to debug issues in production and should be avoided.
|
||
|
||
***
|
||
|
||
### Custom toString() methods
|
||
|
||
You can control how your objects string-ify themselves by defining a custom `toString()` method. This is fine, but you
|
||
need to ensure that your method (1) always succeeds and (2) does not have side-effects. If your method doesn't meet
|
||
these criteria, it's very easy to run into serious problems. For example, if `toString()` calls a method that does an
|
||
assert, assert might try to output the name of the object in which it failed, which of course requires
|
||
calling `toString()`.
|
||
|
||
***
|
||
|
||
### Parentheses
|
||
|
||
Use sparingly and in general only where required by the syntax and semantics. Never use parentheses for unary
|
||
operators such as `delete`, `typeof` and `void` or after keywords such as `return`, `throw` as well
|
||
as others (`case`, in or `new`).
|
||
|
||
***
|
||
|
||
### Strings
|
||
|
||
For consistency single-quotes (') are preferred to double-quotes ("). This is helpful when creating
|
||
strings that include HTML:
|
||
|
||
```
|
||
var msg = 'This is some HTML <div class="makes-sense"></div>';
|
||
```
|
||
|
||
***
|
||
|
||
### Conditional Ternary Operator (shorthand if)
|
||
|
||
Use the ternary operator for assignments or return statements. Use it only in simple conditions and avoid it in complex
|
||
ones. No body likes to wrap his brain around 10 lines of nested ternary operators.
|
||
|
||
**Not recommended**
|
||
```
|
||
if(x === 10) {
|
||
return 'valid';
|
||
} else {
|
||
return 'invalid';
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
return x === 10 ? 'valid' : 'invalid';
|
||
```
|
||
|
||
***
|
||
|
||
## CSS and Sass (SCSS) style rules
|
||
|
||
***
|
||
|
||
### ID and class naming
|
||
|
||
Instead of presentational or cryptic names, always use ID and class names that reflect the purpose of the element in
|
||
question, or that are otherwise generic.
|
||
|
||
Names that are specific and reflect the purpose of the element should be preferred as these are most understandable
|
||
and the least likely to change.
|
||
|
||
Generic names are simply a fallback for elements that have no particular or no meaning different from their siblings.
|
||
They are typically needed as “helpers.”
|
||
|
||
Even though class names and ID's have no semantic meaning to computer interpreters, semantic names are often the right
|
||
choice as they represent the information meaning and don't introduce presentational constraints.
|
||
|
||
**Not recommended**
|
||
```
|
||
.fw-800 {
|
||
font-weight: 800;
|
||
}
|
||
|
||
.red {
|
||
color: red;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.heavy {
|
||
font-weight: 800;
|
||
}
|
||
|
||
.important {
|
||
color: red;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Avoid ID's where possible
|
||
|
||
In general ID's should not be used to apply style. Styles on ID's can't be re-used and you can only use them once per
|
||
page. The only valid location for using an ID would be to identify a page or a whole site. Still you should always
|
||
consider using a class that you use once instead of an id.
|
||
|
||
**Not recommended**
|
||
```
|
||
#content .title {
|
||
font-size: 2em;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.content .title {
|
||
font-size: 2em;
|
||
}
|
||
```
|
||
|
||
One other argument against using ID's would be that selector chains containing ID's are over-prioritized. A selector
|
||
containing just one ID is weighted higher than a selector containing 1000 class names only which makes it very odd.
|
||
|
||
```
|
||
// This selecor is considered with higher priority
|
||
#content .title {
|
||
color: red;
|
||
}
|
||
|
||
// than this selector!
|
||
html body div.content.news-content .title.content-title.important {
|
||
color: blue;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Avoid elements in CSS selectors
|
||
|
||
When building your selectors use clear, precise and sensible class names. Don't use element selectors. If you're only
|
||
concerned about your class names and not about your elements your code gets a lot more maintainable.
|
||
|
||
From a separation of concerns perspective you don't want to dictate the markup / semantics from the presentation layer.
|
||
It might be that a ordered list needs to be changed to an unordered list or that a div will be converted to an article.
|
||
If you only care about sensible class names and don't use element selectors you'd only need to change your markup and
|
||
not your css.
|
||
|
||
**Not recommended**
|
||
```
|
||
div.content > header.content-header > h2.title {
|
||
font-size: 2em;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.content > .content-header > .title {
|
||
font-size: 2em;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Be as precise as possible
|
||
|
||
A lot of front-end developers don't use direct child selectors when they write their selector chains. Sometimes this
|
||
can cause painful design issues and other times it's just a performance eater. However, in any case, it's a very bad
|
||
practice. If you don't write very generic selectors that need to match down to the bottom of the DOM you should always
|
||
consider direct child selectors.
|
||
|
||
Consider the following DOM:
|
||
|
||
```
|
||
<article class="content news-content">
|
||
<span class="title">News event</span>
|
||
<div class="content-body">
|
||
<div class="title content-title">
|
||
Check this out
|
||
</div>
|
||
|
||
<p>This is a news article content</p>
|
||
|
||
<div class="teaser">
|
||
<div class="title">Buy this</div>
|
||
<div class="teaser-content">Yey!</div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
```
|
||
|
||
The following CSS would apply to all three elements that have a title class. This then would need to be overridden again
|
||
with more granular selectors in order to fix the content title and the teaser title.
|
||
|
||
**Not recommended**
|
||
```
|
||
.content .title {
|
||
font-size: 2rem;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.content > .title {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.content > .content-body > .title {
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.content > .content-body > .teaser > .title {
|
||
font-size: 1.2rem;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Shorthand Properties
|
||
|
||
CSS offers a variety of shorthand properties (like font) that should be used whenever possible, even in cases where
|
||
only one value is explicitly set.
|
||
|
||
Using shorthand properties is useful for code efficiency and understandability.
|
||
|
||
**Not recommended**
|
||
```
|
||
border-top-style: none;
|
||
font-family: palatino, georgia, serif;
|
||
font-size: 100%;
|
||
line-height: 1.6;
|
||
padding-bottom: 2em;
|
||
padding-left: 1em;
|
||
padding-right: 1em;
|
||
padding-top: 0;
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
border-top: 0;
|
||
font: 100%/1.6 palatino, georgia, serif;
|
||
padding: 0 1em 2em;
|
||
```
|
||
|
||
***
|
||
|
||
### 0 and units
|
||
|
||
Omit unit specification after “0” values. Do not use units after 0 values unless they are required.
|
||
|
||
**Not recommended**
|
||
```
|
||
padding-bottom: 0px;
|
||
margin: 0em;
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
padding-bottom: 0;
|
||
margin: 0;
|
||
```
|
||
|
||
***
|
||
|
||
### Hexadecimal Notation
|
||
|
||
Use 3 character hexadecimal notation where possible. For color values that permit it, 3 character hexadecimal notation
|
||
is shorter and more succinct.
|
||
|
||
Always use lower case hex digits.
|
||
|
||
**Not recommended**
|
||
```
|
||
color: #FF33AA;
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
color: #f3a;
|
||
```
|
||
|
||
***
|
||
|
||
### ID and Class Name Delimiters
|
||
|
||
Separate words in ID and class names by a hyphen. Do not concatenate words and abbreviations in selectors by any
|
||
characters (including none at all) other than hyphens, in order to improve understanding and scannability.
|
||
|
||
Also as the standard foresees attribute selectors that recognise hyphens as separator of words `[attribute|=value]`
|
||
it's best to stick to the hyphen as separator.
|
||
|
||
**Not recommended**
|
||
```
|
||
.demoimage {}
|
||
.error_status {}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
#video-id {}
|
||
.ads-sample {}
|
||
```
|
||
|
||
***
|
||
|
||
### Hacks
|
||
|
||
Avoid user agent detection as well as CSS “hacks”—try a different approach first. It’s tempting to address styling
|
||
differences over user agent detection or special CSS filters, workarounds, and hacks. Both approaches should be
|
||
considered last resort in order to achieve and maintain an efficient and manageable code base. Put another way, giving
|
||
detection and hacks a free pass will hurt projects in the long run as projects tend to take the way of least
|
||
resistance. That is, allowing and making it easy to use detection and hacks means using detection and hacks more
|
||
frequently—and more frequently is too frequently.
|
||
|
||
***
|
||
|
||
### Declaration Order
|
||
|
||
This example should give a rough outline of how to order CSS properties within a selector. This is important in order
|
||
to guarantee better readability and better scannability.
|
||
|
||
As a best practice we should follow the following ordering (in the same order as the listing):
|
||
|
||
1. structural
|
||
1. display
|
||
1. position, left, top, right etc.
|
||
1. overflow, float, clear etc.
|
||
1. margin, padding
|
||
1. skin
|
||
1. background, border etc.
|
||
1. font, text
|
||
|
||
**Not recommended**
|
||
```
|
||
.box {
|
||
font-family: 'Arial', sans-serif;
|
||
border: 3px solid #ddd;
|
||
left: 30%;
|
||
position: absolute;
|
||
text-transform: uppercase;
|
||
background-color: #eee;
|
||
right: 30%;
|
||
isplay: block;
|
||
font-size: 1.5rem;
|
||
overflow: hidden;
|
||
padding: 1em;
|
||
margin: 1em;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.box {
|
||
display: block;
|
||
position: absolute;
|
||
left: 30%;
|
||
right: 30%;
|
||
overflow: hidden;
|
||
margin: 1em;
|
||
padding: 1em;
|
||
background-color: #eee;
|
||
border: 3px solid #ddd;
|
||
font-family: 'Arial', sans-serif;
|
||
font-size: 1.5rem;
|
||
text-transform: uppercase;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Declaration Stops
|
||
|
||
End every declaration with a semicolon for consistency and extensibility reasons and put each declaration on a new line.
|
||
|
||
**Not recommended**
|
||
```
|
||
.test {
|
||
display: block; height: 100px
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
.test {
|
||
display: block;
|
||
height: 100px;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Property Name Stops
|
||
|
||
Use a space after a property name’s colon. Always use a single space between property and value (but no space between
|
||
property and colon) for consistency reasons.
|
||
|
||
**Not recommended**
|
||
```
|
||
h3 {
|
||
font-weight:bold;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
h3 {
|
||
font-weight: bold;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Selector and Declaration Separation
|
||
|
||
Always start a new line for each selector and declaration.
|
||
|
||
**Not recommended**
|
||
```
|
||
a:focus, a:active {
|
||
position: relative; top: 1px;
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
h1,
|
||
h2,
|
||
h3 {
|
||
font-weight: normal;
|
||
line-height: 1.2;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Rule Separation
|
||
|
||
Always put a blank line (two line breaks) between rules.
|
||
|
||
**Recommended**
|
||
```
|
||
html {
|
||
background: #fff;
|
||
}
|
||
|
||
body {
|
||
margin: auto;
|
||
width: 50%;
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### CSS Quotation Marks
|
||
|
||
Use double ("") rather than single ('') quotation marks for attribute selectors or property values.
|
||
Do not use quotation marks in URI values (url()).
|
||
|
||
**Not recommended**
|
||
```
|
||
@import url('//cdn.com/foundation.css');
|
||
|
||
html {
|
||
font-family: 'open sans', arial, sans-serif;
|
||
}
|
||
|
||
body:after {
|
||
content: 'pause';
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```
|
||
@import url(//cdn.com/foundation.css);
|
||
|
||
html {
|
||
font-family: "open sans", arial, sans-serif;
|
||
}
|
||
|
||
body:after {
|
||
content: "pause";
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Nested selectors (SCSS)
|
||
|
||
In Sass you can nest selectors which is much cleaner and the code becomes much more readable. Nest all selectors but
|
||
try to avoid nesting without any content. If you need to specify some style attributes for a child element where the
|
||
parent element will not receive any styling use a regular CSS selector chain. This will prevent your script to look
|
||
overcomplicated.
|
||
|
||
**Not recommended**
|
||
```scss
|
||
// Not a good example by not making use of nesting at all
|
||
.content {
|
||
display: block;
|
||
}
|
||
|
||
.content > .news-article > .title {
|
||
font-size: 1.2em;
|
||
}
|
||
```
|
||
|
||
**Not recommended**
|
||
```scss
|
||
// Using nesting is better but not in all cases
|
||
// Avoid nesting when there is no attributes and use selector chains instead
|
||
.content {
|
||
display: block;
|
||
|
||
> .news-article {
|
||
> .title {
|
||
font-size: 1.2em;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```scss
|
||
// This example takes the best approach while nesting but use selector chains where possible
|
||
.content {
|
||
display: block;
|
||
|
||
> .news-article > .title {
|
||
font-size: 1.2em;
|
||
}
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Introducing space while nesting (SCSS)
|
||
|
||
If you nest your selectors introduce blank line between your nested selectors and the css attributes.
|
||
|
||
**Not recommended**
|
||
```scss
|
||
.content {
|
||
display: block;
|
||
> .news-article {
|
||
background-color: #eee;
|
||
> .title {
|
||
font-size: 1.2em;
|
||
}
|
||
> .article-footnote {
|
||
font-size: 0.8em;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```scss
|
||
.content {
|
||
display: block;
|
||
|
||
> .news-article {
|
||
background-color: #eee;
|
||
|
||
> .title {
|
||
font-size: 1.2em;
|
||
}
|
||
|
||
> .article-footnote {
|
||
font-size: 0.8em;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Contextual media queries (SCSS)
|
||
|
||
While nesting your selectors you can also make use of contextual media queries within Sass. With Sass you can use media
|
||
queries at any given nesting level. The resulting CSS will be converted so that the media query gets rendered around the
|
||
selector.
|
||
|
||
This technique is very handy and helps to keep media queries in the context where they belong to. With a mobile first
|
||
approach this allows you to write your mobile styles first and then use contextual media queries where ever you need
|
||
them in order to provide the desktop styles.
|
||
|
||
**Not recommended**
|
||
```scss
|
||
// This mobile first example looks like plain CSS where the whole structure of SCSS is repeated
|
||
// on the bottom in a media query. This is error prone and makes maintenance harder as it's not so easy to relate
|
||
// the content in the media query to the content in the upper part (mobile style)
|
||
|
||
.content-page {
|
||
font-size: 1.2rem;
|
||
|
||
> .main {
|
||
background-color: whitesmoke;
|
||
|
||
> .latest-news {
|
||
padding: 1rem;
|
||
|
||
> .news-article {
|
||
padding: 1rem;
|
||
|
||
> .title {
|
||
font-size: 2rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
> .content {
|
||
margin-top: 2rem;
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
|
||
> .page-footer {
|
||
margin-top: 2rem;
|
||
font-size: 1rem;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 641px) {
|
||
.content-page {
|
||
font-size: 1rem;
|
||
|
||
> .main > .latest-news > .news-article > .title {
|
||
font-size: 3rem;
|
||
}
|
||
|
||
> .page-footer {
|
||
font-size: 0.8rem;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Recommended**
|
||
```scss
|
||
// This is the same example as above but here we use contextual media queries in order to put the different styles
|
||
// for different media into the right context.
|
||
|
||
.content-page {
|
||
font-size: 1.2rem;
|
||
|
||
@media screen and (min-width: 641px) {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
> .main {
|
||
background-color: whitesmoke;
|
||
|
||
> .latest-news {
|
||
padding: 1rem;
|
||
|
||
> .news-article {
|
||
padding: 1rem;
|
||
|
||
> .title {
|
||
font-size: 2rem;
|
||
|
||
@media screen and (min-width: 641px) {
|
||
font-size: 3rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
> .content {
|
||
margin-top: 2rem;
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
|
||
> .page-footer {
|
||
margin-top: 2rem;
|
||
font-size: 1rem;
|
||
|
||
@media screen and (min-width: 641px) {
|
||
font-size: 0.8rem;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
***
|
||
|
||
### Nesting order and the parent selector (SCSS)
|
||
|
||
While using the nesting features of Sass it's important to have a clear order to put your nesting in. A SCSS block
|
||
should have the following content order.
|
||
|
||
1. Current selector's style attributes
|
||
1. Pseudo selectors with parent selector (:first-letter, :hover, :active etc)
|
||
1. Pseudo elements (:before and :after)
|
||
1. State classe with parent selector (.selected, .active, .enlarged etc.)
|
||
1. Contextual media queries with Sass
|
||
1. Sub selectors as the last part
|
||
|
||
The following example should illustrate how this ordering will achieve a clear structure while making use of the Sass
|
||
parent selector.
|
||
|
||
**Recommended**
|
||
```scss
|
||
.product-teaser {
|
||
// 1. Style attributes
|
||
display: inline-block;
|
||
padding: 1rem;
|
||
background-color: whitesmoke;
|
||
color: grey;
|
||
|
||
// 2. Pseudo selectors with parent selector
|
||
&:hover {
|
||
color: black;
|
||
}
|
||
|
||
// 3. Pseudo elements with parent selector
|
||
&:before {
|
||
content: "";
|
||
display: block;
|
||
border-top: 1px solid grey;
|
||
}
|
||
|
||
&:after {
|
||
content: "";
|
||
display: block;
|
||
border-top: 1px solid grey;
|
||
}
|
||
|
||
// 4. State classes with parent selector
|
||
&.active {
|
||
background-color: pink;
|
||
color: red;
|
||
|
||
// 4.2. Pseuso selector in state class selector
|
||
&:hover {
|
||
color: darkred;
|
||
}
|
||
}
|
||
|
||
// 5. Contextual media queries
|
||
@media screen and (max-width: 640px) {
|
||
display: block;
|
||
font-size: 2em;
|
||
}
|
||
|
||
// 6. Sub selectors
|
||
> .content > .title {
|
||
font-size: 1.2em;
|
||
|
||
// 6.5. Contextual media queries in sub selector
|
||
@media screen and (max-width: 640px) {
|
||
letter-spacing: 0.2em;
|
||
text-transform: uppercase;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|