diff --git a/CSS/Animations.md b/CSS/Animations.md new file mode 100644 index 0000000..18bee51 --- /dev/null +++ b/CSS/Animations.md @@ -0,0 +1,22 @@ +### Animations + +Favor transitions over animations. Avoid animating other properties than +`opacity` and `transform`. + +```css +/* bad */ +div:hover { + animation: move 1s forwards; +} +@keyframes move { + 100% { + margin-left: 100px; + } +} + +/* good */ +div:hover { + transition: 1s; + transform: translateX(100px); +} +``` \ No newline at end of file diff --git a/CSS/Box_Model.md b/CSS/Box_Model.md new file mode 100644 index 0000000..5d673b7 --- /dev/null +++ b/CSS/Box_Model.md @@ -0,0 +1,19 @@ +### Box model + +The box model should ideally be the same for the entire document. A global +`* { box-sizing: border-box; }` is fine, but don't change the default box model +on specific elements if you can avoid it. + +```css +/* bad */ +div { + width: 100%; + padding: 10px; + box-sizing: border-box; +} + +/* good */ +div { + padding: 10px; +} +``` \ No newline at end of file diff --git a/CSS/Brevity.md b/CSS/Brevity.md new file mode 100644 index 0000000..47875d6 --- /dev/null +++ b/CSS/Brevity.md @@ -0,0 +1,24 @@ +### Brevity + +Keep your code terse. Use shorthand properties and avoid using multiple properties when +it's not needed. + +```css +/* bad */ +div { + transition: all 1s; + top: 50%; + margin-top: -10px; + padding-top: 5px; + padding-right: 10px; + padding-bottom: 20px; + padding-left: 10px; +} + +/* good */ +div { + transition: 1s; + top: calc(50% - 10px); + padding: 5px 10px 20px; +} +``` \ No newline at end of file diff --git a/CSS/Colors.md b/CSS/Colors.md new file mode 100644 index 0000000..bf26df1 --- /dev/null +++ b/CSS/Colors.md @@ -0,0 +1,15 @@ +### Colors + +If you need transparency, use `rgba`. Otherwise, always use the hexadecimal format. + +```css +/* bad */ +div { + color: hsl(103, 54%, 43%); +} + +/* good */ +div { + color: #5a3; +} +``` \ No newline at end of file diff --git a/CSS/Drawing.md b/CSS/Drawing.md new file mode 100644 index 0000000..7550c9c --- /dev/null +++ b/CSS/Drawing.md @@ -0,0 +1,20 @@ +### Drawing + +Avoid HTTP requests when the resources are easily replicable with CSS. + +```css +/* bad */ +div::before { + content: url(white-circle.svg); +} + +/* good */ +div::before { + content: ""; + display: block; + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; +} +``` \ No newline at end of file diff --git a/CSS/Flow.md b/CSS/Flow.md new file mode 100644 index 0000000..ad3bb32 --- /dev/null +++ b/CSS/Flow.md @@ -0,0 +1,34 @@ +### Flow + +Don't change the default behavior of an element if you can avoid it. Keep elements in the +natural document flow as much as you can. For example, removing the white-space below an +image shouldn't make you change its default display: + +```css +/* bad */ +img { + display: block; +} + +/* good */ +img { + vertical-align: middle; +} +``` + +Similarly, don't take an element off the flow if you can avoid it. + +```css +/* bad */ +div { + width: 100px; + position: absolute; + right: 0; +} + +/* good */ +div { + width: 100px; + margin-left: auto; +} +``` diff --git a/CSS/Hacks.md b/CSS/Hacks.md new file mode 100644 index 0000000..6a9ea0d --- /dev/null +++ b/CSS/Hacks.md @@ -0,0 +1,17 @@ +### Hacks + +Don't use them. + +```css +/* bad */ +div { + // position: relative; + transform: translateZ(0); +} + +/* good */ +div { + /* position: relative; */ + will-change: transform; +} +``` \ No newline at end of file diff --git a/CSS/Inheritance.md b/CSS/Inheritance.md new file mode 100644 index 0000000..ab10947 --- /dev/null +++ b/CSS/Inheritance.md @@ -0,0 +1,15 @@ +### Inheritance + +Don't duplicate style declarations that can be inherited. + +```css +/* bad */ +div h1, div p { + text-shadow: 0 1px 0 #fff; +} + +/* good */ +div { + text-shadow: 0 1px 0 #fff; +} +``` \ No newline at end of file diff --git a/CSS/Language.md b/CSS/Language.md new file mode 100644 index 0000000..fb49318 --- /dev/null +++ b/CSS/Language.md @@ -0,0 +1,15 @@ +### Language + +Prefer English over math. + +```css +/* bad */ +:nth-child(2n + 1) { + transform: rotate(360deg); +} + +/* good */ +:nth-child(odd) { + transform: rotate(1turn); +} +``` \ No newline at end of file diff --git a/CSS/Overriding.md b/CSS/Overriding.md new file mode 100644 index 0000000..bbb1ed0 --- /dev/null +++ b/CSS/Overriding.md @@ -0,0 +1,18 @@ +### Overriding + +Overriding styles makes selectors and debugging harder. Avoid it when possible. + +```css +/* bad */ +li { + visibility: hidden; +} +li:first-child { + visibility: visible; +} + +/* good */ +li + li { + visibility: hidden; +} +``` \ No newline at end of file diff --git a/CSS/Positioning.md b/CSS/Positioning.md new file mode 100644 index 0000000..8b0bb68 --- /dev/null +++ b/CSS/Positioning.md @@ -0,0 +1,5 @@ +### Positioning + +There are many ways to position elements in CSS. Favor modern layout specifications +such as Flexbox and Grid, and avoid removing elements from the normal document flow, for example +with `position: absolute`. \ No newline at end of file diff --git a/CSS/Selectors.md b/CSS/Selectors.md new file mode 100644 index 0000000..070dc8d --- /dev/null +++ b/CSS/Selectors.md @@ -0,0 +1,27 @@ +### Selectors + +Minimize selectors tightly coupled to the DOM. Consider adding a class to the elements +you want to match when your selector exceeds 3 structural pseudo-classes, descendant or +sibling combinators. + +```css +/* bad */ +div:first-of-type :last-child > p ~ * + +/* good */ +div:first-of-type .info +``` + +Avoid overloading your selectors when you don't need to. + +```css +/* bad */ +img[src$=svg], ul > li:first-child { + opacity: 0; +} + +/* good */ +[src$=svg], ul > :first-child { + opacity: 0; +} +``` \ No newline at end of file diff --git a/CSS/Semicolons.md b/CSS/Semicolons.md new file mode 100644 index 0000000..b5e1e2b --- /dev/null +++ b/CSS/Semicolons.md @@ -0,0 +1,15 @@ +### Semicolons + +While the semicolon is technically a separator in CSS, always treat it as a terminator. + +```css +/* bad */ +div { + color: red +} + +/* good */ +div { + color: red; +} +``` diff --git a/CSS/Specificity.md b/CSS/Specificity.md new file mode 100644 index 0000000..5f52158 --- /dev/null +++ b/CSS/Specificity.md @@ -0,0 +1,22 @@ +### Specificity + +Don't make values and selectors hard to override. Minimize the use of `id`'s +and avoid `!important`. + +```css +/* bad */ +.bar { + color: green !important; +} +.foo { + color: red; +} + +/* good */ +.foo.bar { + color: green; +} +.foo { + color: red; +} +``` \ No newline at end of file diff --git a/CSS/Units.md b/CSS/Units.md new file mode 100644 index 0000000..abf661a --- /dev/null +++ b/CSS/Units.md @@ -0,0 +1,22 @@ +### Units + +Use unitless values when you can. Favor `rem` if you use relative units. Prefer seconds over +milliseconds. + +```css +/* bad */ +div { + margin: 0px; + font-size: .9em; + line-height: 22px; + transition: 500ms; +} + +/* good */ +div { + margin: 0; + font-size: .9rem; + line-height: 1.5; + transition: .5s; +} +``` \ No newline at end of file diff --git a/CSS/Vendor_prefix.md b/CSS/Vendor_prefix.md new file mode 100644 index 0000000..793c449 --- /dev/null +++ b/CSS/Vendor_prefix.md @@ -0,0 +1,25 @@ +### Vendor prefixes + +Kill obsolete vendor prefixes aggressively. If you need to use them, insert them before the +standard property. + +```css +/* bad */ +div { + transform: scale(2); + -webkit-transform: scale(2); + -moz-transform: scale(2); + -ms-transform: scale(2); + transition: 1s; + -webkit-transition: 1s; + -moz-transition: 1s; + -ms-transition: 1s; +} + +/* good */ +div { + -webkit-transform: scale(2); + transform: scale(2); + transition: 1s; +} +``` \ No newline at end of file diff --git a/HTML/Accessibility.md b/HTML/Accessibility.md new file mode 100644 index 0000000..ea64067 --- /dev/null +++ b/HTML/Accessibility.md @@ -0,0 +1,17 @@ +### Accessibility + +Accessibility shouldn't be an afterthought. You don't have to be a WCAG expert to improve your +website, you can start immediately by fixing the little things that make a huge difference, such as: + +* learning to use the `alt` attribute properly +* making sure your links and buttons are marked as such (no `
` atrocities) +* not relying exclusively on colors to communicate information +* explicitly labelling form controls + +```html + +

Logo

+ + +

Company

+``` \ No newline at end of file diff --git a/HTML/Brevity.md b/HTML/Brevity.md new file mode 100644 index 0000000..122d3b0 --- /dev/null +++ b/HTML/Brevity.md @@ -0,0 +1,38 @@ +### Brevity + +Keep your code terse. Forget about your old XHTML habits. + +```html + + + + + + Contact + + + +

Contact me

+ + + + + + + + + + Contact + + +

Contact me

+ + + +``` \ No newline at end of file diff --git a/HTML/Language_and_Character_Encoding.md b/HTML/Language_and_Character_Encoding.md new file mode 100644 index 0000000..f702ac4 --- /dev/null +++ b/HTML/Language_and_Character_Encoding.md @@ -0,0 +1,21 @@ +### Language & character encoding + +While defining the language is optional, it's recommended to always declare +it on the root element. + +The HTML standard requires that pages use the UTF-8 character encoding. +It has to be declared, and although it can be declared in the Content-Type HTTP header, +it is recommended to always declare it at the document level. + +```html + + +Hello, world. + + + + + + Hello, world. + +``` \ No newline at end of file diff --git a/HTML/Performance.md b/HTML/Performance.md new file mode 100644 index 0000000..59e68be --- /dev/null +++ b/HTML/Performance.md @@ -0,0 +1,23 @@ +### Performance + +Unless there's a valid reason for loading your scripts before your content, don't block the +rendering of your page. If your style sheet is heavy, isolate the styles that are absolutely +required initially and defer the loading of the secondary declarations in a separate style sheet. +Two HTTP requests is significantly slower than one, but the perception of speed is the most +important factor. + +```html + + + + +Hello, world. +

...

+ + + + +Hello, world. +

...

+ +``` \ No newline at end of file diff --git a/HTML/Semantics.md b/HTML/Semantics.md new file mode 100644 index 0000000..112e773 --- /dev/null +++ b/HTML/Semantics.md @@ -0,0 +1,44 @@ +### Semantics + +HTML5 provides us with lots of semantic elements aimed to describe precisely the content. Make sure you benefit from its rich vocabulary. + +```html + +
+
+
+

Blog post

+

Published: 21st Feb, 2015

+
+

+
+
+ + +
+
+
+

Blog post

+

Published:

+
+

+
+
+``` + +Make sure you understand the semantics of the elements you're using. It's worse to use a semantic +element in a wrong way than staying neutral. + +```html + +

+
+ Company +
+

+ + +

+ Company +

+``` \ No newline at end of file diff --git a/JS/Arguments.md b/JS/Arguments.md new file mode 100644 index 0000000..ac961c2 --- /dev/null +++ b/JS/Arguments.md @@ -0,0 +1,30 @@ +### Arguments + +Forget about the `arguments` object. The rest parameter is always a better option because: + +1. it's named, so it gives you a better idea of the arguments the function is expecting +2. it's a real array, which makes it easier to use. + +```javascript +// bad +const sortNumbers = () => + Array.prototype.slice.call(arguments).sort(); + +// good +const sortNumbers = (...numbers) => numbers.sort(); +``` + +### Apply + +Forget about `apply()`. Use the spread operator instead. + +```javascript +const greet = (first, last) => `Hi ${first} ${last}`; +const person = ["John", "Doe"]; + +// bad +greet.apply(null, person); + +// good +greet(...person); +``` \ No newline at end of file diff --git a/JS/Bind.md b/JS/Bind.md new file mode 100644 index 0000000..60aa7e1 --- /dev/null +++ b/JS/Bind.md @@ -0,0 +1,34 @@ +### Bind + +Don't `bind()` when there's a more idiomatic approach. + +```javascript +// bad +["foo", "bar"].forEach(func.bind(this)); + +// good +["foo", "bar"].forEach(func, this); +``` +```javascript +// bad +const person = { + first: "John", + last: "Doe", + greet() { + const full = function() { + return `${this.first} ${this.last}`; + }.bind(this); + return `Hello ${full()}`; + } +} + +// good +const person = { + first: "John", + last: "Doe", + greet() { + const full = () => `${this.first} ${this.last}`; + return `Hello ${full()}`; + } +} +``` \ No newline at end of file diff --git a/JS/Caching.md b/JS/Caching.md new file mode 100644 index 0000000..1ced81c --- /dev/null +++ b/JS/Caching.md @@ -0,0 +1,20 @@ +### Caching + +Cache feature tests, large data structures and any expensive operation. + +```javascript +// bad +const contains = (arr, value) => + Array.prototype.includes + ? arr.includes(value) + : arr.some(el => el === value); +contains(["foo", "bar"], "baz"); // => false + +// good +const contains = (() => + Array.prototype.includes + ? (arr, value) => arr.includes(value) + : (arr, value) => arr.some(el => el === value) +)(); +contains(["foo", "bar"], "baz"); // => false +``` \ No newline at end of file diff --git a/JS/Code_Reuse.md b/JS/Code_Reuse.md new file mode 100644 index 0000000..5394fbe --- /dev/null +++ b/JS/Code_Reuse.md @@ -0,0 +1,22 @@ +### Code reuse + +Don't be afraid of creating lots of small, highly composable and reusable functions. + +```javascript +// bad +arr[arr.length - 1]; + +// good +const first = arr => arr[0]; +const last = arr => first(arr.slice(-1)); +last(arr); +``` +```javascript +// bad +const product = (a, b) => a * b; +const triple = n => n * 3; + +// good +const product = (a, b) => a * b; +const triple = product.bind(null, 3); +``` \ No newline at end of file diff --git a/JS/Coersion.md b/JS/Coersion.md new file mode 100644 index 0000000..36aa852 --- /dev/null +++ b/JS/Coersion.md @@ -0,0 +1,11 @@ +### Coercion + +Embrace implicit coercion when it makes sense. Avoid it otherwise. Don't cargo-cult. + +```javascript +// bad +if (x === undefined || x === null) { ... } + +// good +if (x == undefined) { ... } +``` \ No newline at end of file diff --git a/JS/Composition.md b/JS/Composition.md new file mode 100644 index 0000000..7ebf0f5 --- /dev/null +++ b/JS/Composition.md @@ -0,0 +1,16 @@ +### Composition + +Avoid multiple nested function calls. Use composition instead. + +```javascript +const plus1 = a => a + 1; +const mult2 = a => a * 2; + +// bad +mult2(plus1(5)); // => 12 + +// good +const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val); +const addThenMult = pipeline(plus1, mult2); +addThenMult(5); // => 12 +``` \ No newline at end of file diff --git a/JS/Conditions.md b/JS/Conditions.md new file mode 100644 index 0000000..594ca6e --- /dev/null +++ b/JS/Conditions.md @@ -0,0 +1,23 @@ +### Conditions + +Favor IIFE's and return statements over if, else if, else and switch statements. + +```javascript +// bad +var grade; +if (result < 50) + grade = "bad"; +else if (result < 90) + grade = "good"; +else + grade = "excellent"; + +// good +const grade = (() => { + if (result < 50) + return "bad"; + if (result < 90) + return "good"; + return "excellent"; +})(); +``` \ No newline at end of file diff --git a/JS/Curry.md b/JS/Curry.md new file mode 100644 index 0000000..de7bdf0 --- /dev/null +++ b/JS/Curry.md @@ -0,0 +1,14 @@ +### Curry + +Currying is a powerful but foreign paradigm for many developers. Don't abuse it as its appropriate +use cases are fairly unusual. + +```javascript +// bad +const sum = a => b => a + b; +sum(5)(3); // => 8 + +// good +const sum = (a, b) => a + b; +sum(5, 3); // => 8 +``` \ No newline at end of file diff --git a/JS/Dependencies.md b/JS/Dependencies.md new file mode 100644 index 0000000..14a3acd --- /dev/null +++ b/JS/Dependencies.md @@ -0,0 +1,20 @@ +### Dependencies + +Minimize dependencies. Third-party is code you don't know. Don't load an entire library for just a couple of methods easily replicable: + +```javascript +// bad +var _ = require("underscore"); +_.compact(["foo", 0])); +_.unique(["foo", "foo"]); +_.union(["foo"], ["bar"], ["foo"]); + +// good +const compact = arr => arr.filter(el => el); +const unique = arr => [...new Set(arr)]; +const union = (...arr) => unique([].concat(...arr)); + +compact(["foo", 0]); +unique(["foo", "foo"]); +union(["foo"], ["bar"], ["foo"]); +``` \ No newline at end of file diff --git a/JS/Higher_Order_Functions.md b/JS/Higher_Order_Functions.md new file mode 100644 index 0000000..6b8d3e9 --- /dev/null +++ b/JS/Higher_Order_Functions.md @@ -0,0 +1,11 @@ +### Higher-order functions + +Avoid nesting functions when you don't have to. + +```javascript +// bad +[1, 2, 3].map(num => String(num)); + +// good +[1, 2, 3].map(String); +``` \ No newline at end of file diff --git a/JS/Loops.md b/JS/Loops.md new file mode 100644 index 0000000..e2671ad --- /dev/null +++ b/JS/Loops.md @@ -0,0 +1,51 @@ +### Loops + +Don't use loops as they force you to use mutable objects. Rely on `array.prototype` methods. + +```javascript +// bad +const sum = arr => { + var sum = 0; + var i = -1; + for (;arr[++i];) { + sum += arr[i]; + } + return sum; +}; + +sum([1, 2, 3]); // => 6 + +// good +const sum = arr => + arr.reduce((x, y) => x + y); + +sum([1, 2, 3]); // => 6 +``` +If you can't, or if using `array.prototype` methods is arguably abusive, use recursion. + +```javascript +// bad +const createDivs = howMany => { + while (howMany--) { + document.body.insertAdjacentHTML("beforeend", "
"); + } +}; +createDivs(5); + +// bad +const createDivs = howMany => + [...Array(howMany)].forEach(() => + document.body.insertAdjacentHTML("beforeend", "
") + ); +createDivs(5); + +// good +const createDivs = howMany => { + if (!howMany) return; + document.body.insertAdjacentHTML("beforeend", "
"); + return createDivs(howMany - 1); +}; +createDivs(5); +``` + +Here's a [generic loop function](https://gist.github.com/bendc/6cb2db4a44ec30208e86) making recursion easier to use. \ No newline at end of file diff --git a/JS/Object_Iteratiom.md b/JS/Object_Iteratiom.md new file mode 100644 index 0000000..f392dc5 --- /dev/null +++ b/JS/Object_Iteratiom.md @@ -0,0 +1,22 @@ +### Object iteration + +Avoid `for...in` when you can. + +```javascript +const shared = { foo: "foo" }; +const obj = Object.create(shared, { + bar: { + value: "bar", + enumerable: true + } +}); + +// bad +for (var prop in obj) { + if (obj.hasOwnProperty(prop)) + console.log(prop); +} + +// good +Object.keys(obj).forEach(prop => console.log(prop)); +``` diff --git a/JS/Objects_As_Maps.md b/JS/Objects_As_Maps.md new file mode 100644 index 0000000..8029ad4 --- /dev/null +++ b/JS/Objects_As_Maps.md @@ -0,0 +1,25 @@ +### Objects as Maps + +While objects have legitimate use cases, maps are usually a better, more powerful choice. When in +doubt, use a `Map`. + +```javascript +// bad +const me = { + name: "Ben", + age: 30 +}; +var meSize = Object.keys(me).length; +meSize; // => 2 +me.country = "Belgium"; +meSize++; +meSize; // => 3 + +// good +const me = new Map(); +me.set("name", "Ben"); +me.set("age", 30); +me.size; // => 2 +me.set("country", "Belgium"); +me.size; // => 3 +``` \ No newline at end of file diff --git a/JS/Performance.md b/JS/Performance.md new file mode 100644 index 0000000..8dae8e9 --- /dev/null +++ b/JS/Performance.md @@ -0,0 +1,25 @@ +### Performance + +Favor readability, correctness and expressiveness over performance. JavaScript will basically never +be your performance bottleneck. Optimize things like image compression, network access and DOM +reflows instead. If you remember just one guideline from this document, choose this one. + +```javascript +// bad (albeit way faster) +const arr = [1, 2, 3, 4]; +const len = arr.length; +var i = -1; +var result = []; +while (++i < len) { + var n = arr[i]; + if (n % 2 > 0) continue; + result.push(n * n); +} + +// good +const arr = [1, 2, 3, 4]; +const isEven = n => n % 2 == 0; +const square = n => n * n; + +const result = arr.filter(isEven).map(square); +``` \ No newline at end of file diff --git a/JS/Readability.md b/JS/Readability.md new file mode 100644 index 0000000..17ba9ab --- /dev/null +++ b/JS/Readability.md @@ -0,0 +1,25 @@ +### Readability + +Don't obfuscate the intent of your code by using seemingly smart tricks. + +```javascript +// bad +foo || doSomething(); + +// good +if (!foo) doSomething(); +``` +```javascript +// bad +void function() { /* IIFE */ }(); + +// good +(function() { /* IIFE */ }()); +``` +```javascript +// bad +const n = ~~3.14; + +// good +const n = Math.floor(3.14); +``` diff --git a/JS/Statelessness.md b/JS/Statelessness.md new file mode 100644 index 0000000..865381d --- /dev/null +++ b/JS/Statelessness.md @@ -0,0 +1,27 @@ +### Statelessness + +Try to keep your functions pure. All functions should ideally produce no side-effects, use no outside data and return new objects instead of mutating existing ones. + +```javascript +// bad +const merge = (target, ...sources) => Object.assign(target, ...sources); +merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" } + +// good +const merge = (...sources) => Object.assign({}, ...sources); +merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" } +``` + +### Natives + +Rely on native methods as much as possible. + +```javascript +// bad +const toArray = obj => [].slice.call(obj); + +// good +const toArray = (() => + Array.from ? Array.from : obj => [].slice.call(obj) +)(); +``` \ No newline at end of file diff --git a/JS/Variables.md b/JS/Variables.md new file mode 100644 index 0000000..a2aded2 --- /dev/null +++ b/JS/Variables.md @@ -0,0 +1,13 @@ +### Variables + +Favor `const` over `let` and `let` over `var`. + +```javascript +// bad +var me = new Map(); +me.set("name", "Ben").set("country", "Belgium"); + +// good +const me = new Map(); +me.set("name", "Ben").set("country", "Belgium"); +``` diff --git a/README.md b/README.md index f502d0e..eda32d8 100644 --- a/README.md +++ b/README.md @@ -1,892 +1,3 @@ # Frontend Guidelines -## HTML - -### Semantics - -HTML5 provides us with lots of semantic elements aimed to describe precisely the content. Make sure you benefit from its rich vocabulary. - -```html - -
-
-
-

Blog post

-

Published: 21st Feb, 2015

-
-

-
-
- - -
-
-
-

Blog post

-

Published:

-
-

-
-
-``` - -Make sure you understand the semantics of the elements you're using. It's worse to use a semantic -element in a wrong way than staying neutral. - -```html - -

-
- Company -
-

- - -

- Company -

-``` - -### Brevity - -Keep your code terse. Forget about your old XHTML habits. - -```html - - - - - - Contact - - - -

Contact me

- - - - - - - - - - Contact - - -

Contact me

- - - -``` - -### Accessibility - -Accessibility shouldn't be an afterthought. You don't have to be a WCAG expert to improve your -website, you can start immediately by fixing the little things that make a huge difference, such as: - -* learning to use the `alt` attribute properly -* making sure your links and buttons are marked as such (no `
` atrocities) -* not relying exclusively on colors to communicate information -* explicitly labelling form controls - -```html - -

Logo

- - -

Company

-``` - -### Language & character encoding - -While defining the language is optional, it's recommended to always declare -it on the root element. - -The HTML standard requires that pages use the UTF-8 character encoding. -It has to be declared, and although it can be declared in the Content-Type HTTP header, -it is recommended to always declare it at the document level. - -```html - - -Hello, world. - - - - - - Hello, world. - -``` - -### Performance - -Unless there's a valid reason for loading your scripts before your content, don't block the -rendering of your page. If your style sheet is heavy, isolate the styles that are absolutely -required initially and defer the loading of the secondary declarations in a separate style sheet. -Two HTTP requests is significantly slower than one, but the perception of speed is the most -important factor. - -```html - - - - -Hello, world. -

...

- - - - -Hello, world. -

...

- -``` - -## CSS - -### Semicolons - -While the semicolon is technically a separator in CSS, always treat it as a terminator. - -```css -/* bad */ -div { - color: red -} - -/* good */ -div { - color: red; -} -``` - -### Box model - -The box model should ideally be the same for the entire document. A global -`* { box-sizing: border-box; }` is fine, but don't change the default box model -on specific elements if you can avoid it. - -```css -/* bad */ -div { - width: 100%; - padding: 10px; - box-sizing: border-box; -} - -/* good */ -div { - padding: 10px; -} -``` - -### Flow - -Don't change the default behavior of an element if you can avoid it. Keep elements in the -natural document flow as much as you can. For example, removing the white-space below an -image shouldn't make you change its default display: - -```css -/* bad */ -img { - display: block; -} - -/* good */ -img { - vertical-align: middle; -} -``` - -Similarly, don't take an element off the flow if you can avoid it. - -```css -/* bad */ -div { - width: 100px; - position: absolute; - right: 0; -} - -/* good */ -div { - width: 100px; - margin-left: auto; -} -``` - -### Positioning - -There are many ways to position elements in CSS. Favor modern layout specifications -such as Flexbox and Grid, and avoid removing elements from the normal document flow, for example -with `position: absolute`. - -### Selectors - -Minimize selectors tightly coupled to the DOM. Consider adding a class to the elements -you want to match when your selector exceeds 3 structural pseudo-classes, descendant or -sibling combinators. - -```css -/* bad */ -div:first-of-type :last-child > p ~ * - -/* good */ -div:first-of-type .info -``` - -Avoid overloading your selectors when you don't need to. - -```css -/* bad */ -img[src$=svg], ul > li:first-child { - opacity: 0; -} - -/* good */ -[src$=svg], ul > :first-child { - opacity: 0; -} -``` - -### Specificity - -Don't make values and selectors hard to override. Minimize the use of `id`'s -and avoid `!important`. - -```css -/* bad */ -.bar { - color: green !important; -} -.foo { - color: red; -} - -/* good */ -.foo.bar { - color: green; -} -.foo { - color: red; -} -``` - -### Overriding - -Overriding styles makes selectors and debugging harder. Avoid it when possible. - -```css -/* bad */ -li { - visibility: hidden; -} -li:first-child { - visibility: visible; -} - -/* good */ -li + li { - visibility: hidden; -} -``` - -### Inheritance - -Don't duplicate style declarations that can be inherited. - -```css -/* bad */ -div h1, div p { - text-shadow: 0 1px 0 #fff; -} - -/* good */ -div { - text-shadow: 0 1px 0 #fff; -} -``` - -### Brevity - -Keep your code terse. Use shorthand properties and avoid using multiple properties when -it's not needed. - -```css -/* bad */ -div { - transition: all 1s; - top: 50%; - margin-top: -10px; - padding-top: 5px; - padding-right: 10px; - padding-bottom: 20px; - padding-left: 10px; -} - -/* good */ -div { - transition: 1s; - top: calc(50% - 10px); - padding: 5px 10px 20px; -} -``` - -### Language - -Prefer English over math. - -```css -/* bad */ -:nth-child(2n + 1) { - transform: rotate(360deg); -} - -/* good */ -:nth-child(odd) { - transform: rotate(1turn); -} -``` - -### Vendor prefixes - -Kill obsolete vendor prefixes aggressively. If you need to use them, insert them before the -standard property. - -```css -/* bad */ -div { - transform: scale(2); - -webkit-transform: scale(2); - -moz-transform: scale(2); - -ms-transform: scale(2); - transition: 1s; - -webkit-transition: 1s; - -moz-transition: 1s; - -ms-transition: 1s; -} - -/* good */ -div { - -webkit-transform: scale(2); - transform: scale(2); - transition: 1s; -} -``` - -### Animations - -Favor transitions over animations. Avoid animating other properties than -`opacity` and `transform`. - -```css -/* bad */ -div:hover { - animation: move 1s forwards; -} -@keyframes move { - 100% { - margin-left: 100px; - } -} - -/* good */ -div:hover { - transition: 1s; - transform: translateX(100px); -} -``` - -### Units - -Use unitless values when you can. Favor `rem` if you use relative units. Prefer seconds over -milliseconds. - -```css -/* bad */ -div { - margin: 0px; - font-size: .9em; - line-height: 22px; - transition: 500ms; -} - -/* good */ -div { - margin: 0; - font-size: .9rem; - line-height: 1.5; - transition: .5s; -} -``` - -### Colors - -If you need transparency, use `rgba`. Otherwise, always use the hexadecimal format. - -```css -/* bad */ -div { - color: hsl(103, 54%, 43%); -} - -/* good */ -div { - color: #5a3; -} -``` - -### Drawing - -Avoid HTTP requests when the resources are easily replicable with CSS. - -```css -/* bad */ -div::before { - content: url(white-circle.svg); -} - -/* good */ -div::before { - content: ""; - display: block; - width: 20px; - height: 20px; - border-radius: 50%; - background: #fff; -} -``` - -### Hacks - -Don't use them. - -```css -/* bad */ -div { - // position: relative; - transform: translateZ(0); -} - -/* good */ -div { - /* position: relative; */ - will-change: transform; -} -``` - -## JavaScript - -### Performance - -Favor readability, correctness and expressiveness over performance. JavaScript will basically never -be your performance bottleneck. Optimize things like image compression, network access and DOM -reflows instead. If you remember just one guideline from this document, choose this one. - -```javascript -// bad (albeit way faster) -const arr = [1, 2, 3, 4]; -const len = arr.length; -var i = -1; -var result = []; -while (++i < len) { - var n = arr[i]; - if (n % 2 > 0) continue; - result.push(n * n); -} - -// good -const arr = [1, 2, 3, 4]; -const isEven = n => n % 2 == 0; -const square = n => n * n; - -const result = arr.filter(isEven).map(square); -``` - -### Statelessness - -Try to keep your functions pure. All functions should ideally produce no side-effects, use no outside data and return new objects instead of mutating existing ones. - -```javascript -// bad -const merge = (target, ...sources) => Object.assign(target, ...sources); -merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" } - -// good -const merge = (...sources) => Object.assign({}, ...sources); -merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" } -``` - -### Natives - -Rely on native methods as much as possible. - -```javascript -// bad -const toArray = obj => [].slice.call(obj); - -// good -const toArray = (() => - Array.from ? Array.from : obj => [].slice.call(obj) -)(); -``` - -### Coercion - -Embrace implicit coercion when it makes sense. Avoid it otherwise. Don't cargo-cult. - -```javascript -// bad -if (x === undefined || x === null) { ... } - -// good -if (x == undefined) { ... } -``` - -### Loops - -Don't use loops as they force you to use mutable objects. Rely on `array.prototype` methods. - -```javascript -// bad -const sum = arr => { - var sum = 0; - var i = -1; - for (;arr[++i];) { - sum += arr[i]; - } - return sum; -}; - -sum([1, 2, 3]); // => 6 - -// good -const sum = arr => - arr.reduce((x, y) => x + y); - -sum([1, 2, 3]); // => 6 -``` -If you can't, or if using `array.prototype` methods is arguably abusive, use recursion. - -```javascript -// bad -const createDivs = howMany => { - while (howMany--) { - document.body.insertAdjacentHTML("beforeend", "
"); - } -}; -createDivs(5); - -// bad -const createDivs = howMany => - [...Array(howMany)].forEach(() => - document.body.insertAdjacentHTML("beforeend", "
") - ); -createDivs(5); - -// good -const createDivs = howMany => { - if (!howMany) return; - document.body.insertAdjacentHTML("beforeend", "
"); - return createDivs(howMany - 1); -}; -createDivs(5); -``` - -Here's a [generic loop function](https://gist.github.com/bendc/6cb2db4a44ec30208e86) making recursion easier to use. - -### Arguments - -Forget about the `arguments` object. The rest parameter is always a better option because: - -1. it's named, so it gives you a better idea of the arguments the function is expecting -2. it's a real array, which makes it easier to use. - -```javascript -// bad -const sortNumbers = () => - Array.prototype.slice.call(arguments).sort(); - -// good -const sortNumbers = (...numbers) => numbers.sort(); -``` - -### Apply - -Forget about `apply()`. Use the spread operator instead. - -```javascript -const greet = (first, last) => `Hi ${first} ${last}`; -const person = ["John", "Doe"]; - -// bad -greet.apply(null, person); - -// good -greet(...person); -``` - -### Bind - -Don't `bind()` when there's a more idiomatic approach. - -```javascript -// bad -["foo", "bar"].forEach(func.bind(this)); - -// good -["foo", "bar"].forEach(func, this); -``` -```javascript -// bad -const person = { - first: "John", - last: "Doe", - greet() { - const full = function() { - return `${this.first} ${this.last}`; - }.bind(this); - return `Hello ${full()}`; - } -} - -// good -const person = { - first: "John", - last: "Doe", - greet() { - const full = () => `${this.first} ${this.last}`; - return `Hello ${full()}`; - } -} -``` - -### Higher-order functions - -Avoid nesting functions when you don't have to. - -```javascript -// bad -[1, 2, 3].map(num => String(num)); - -// good -[1, 2, 3].map(String); -``` - -### Composition - -Avoid multiple nested function calls. Use composition instead. - -```javascript -const plus1 = a => a + 1; -const mult2 = a => a * 2; - -// bad -mult2(plus1(5)); // => 12 - -// good -const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val); -const addThenMult = pipeline(plus1, mult2); -addThenMult(5); // => 12 -``` - -### Caching - -Cache feature tests, large data structures and any expensive operation. - -```javascript -// bad -const contains = (arr, value) => - Array.prototype.includes - ? arr.includes(value) - : arr.some(el => el === value); -contains(["foo", "bar"], "baz"); // => false - -// good -const contains = (() => - Array.prototype.includes - ? (arr, value) => arr.includes(value) - : (arr, value) => arr.some(el => el === value) -)(); -contains(["foo", "bar"], "baz"); // => false -``` - -### Variables - -Favor `const` over `let` and `let` over `var`. - -```javascript -// bad -var me = new Map(); -me.set("name", "Ben").set("country", "Belgium"); - -// good -const me = new Map(); -me.set("name", "Ben").set("country", "Belgium"); -``` - -### Conditions - -Favor IIFE's and return statements over if, else if, else and switch statements. - -```javascript -// bad -var grade; -if (result < 50) - grade = "bad"; -else if (result < 90) - grade = "good"; -else - grade = "excellent"; - -// good -const grade = (() => { - if (result < 50) - return "bad"; - if (result < 90) - return "good"; - return "excellent"; -})(); -``` - -### Object iteration - -Avoid `for...in` when you can. - -```javascript -const shared = { foo: "foo" }; -const obj = Object.create(shared, { - bar: { - value: "bar", - enumerable: true - } -}); - -// bad -for (var prop in obj) { - if (obj.hasOwnProperty(prop)) - console.log(prop); -} - -// good -Object.keys(obj).forEach(prop => console.log(prop)); -``` - -### Objects as Maps - -While objects have legitimate use cases, maps are usually a better, more powerful choice. When in -doubt, use a `Map`. - -```javascript -// bad -const me = { - name: "Ben", - age: 30 -}; -var meSize = Object.keys(me).length; -meSize; // => 2 -me.country = "Belgium"; -meSize++; -meSize; // => 3 - -// good -const me = new Map(); -me.set("name", "Ben"); -me.set("age", 30); -me.size; // => 2 -me.set("country", "Belgium"); -me.size; // => 3 -``` - -### Curry - -Currying is a powerful but foreign paradigm for many developers. Don't abuse it as its appropriate -use cases are fairly unusual. - -```javascript -// bad -const sum = a => b => a + b; -sum(5)(3); // => 8 - -// good -const sum = (a, b) => a + b; -sum(5, 3); // => 8 -``` - -### Readability - -Don't obfuscate the intent of your code by using seemingly smart tricks. - -```javascript -// bad -foo || doSomething(); - -// good -if (!foo) doSomething(); -``` -```javascript -// bad -void function() { /* IIFE */ }(); - -// good -(function() { /* IIFE */ }()); -``` -```javascript -// bad -const n = ~~3.14; - -// good -const n = Math.floor(3.14); -``` - -### Code reuse - -Don't be afraid of creating lots of small, highly composable and reusable functions. - -```javascript -// bad -arr[arr.length - 1]; - -// good -const first = arr => arr[0]; -const last = arr => first(arr.slice(-1)); -last(arr); -``` -```javascript -// bad -const product = (a, b) => a * b; -const triple = n => n * 3; - -// good -const product = (a, b) => a * b; -const triple = product.bind(null, 3); -``` - -### Dependencies - -Minimize dependencies. Third-party is code you don't know. Don't load an entire library for just a couple of methods easily replicable: - -```javascript -// bad -var _ = require("underscore"); -_.compact(["foo", 0])); -_.unique(["foo", "foo"]); -_.union(["foo"], ["bar"], ["foo"]); - -// good -const compact = arr => arr.filter(el => el); -const unique = arr => [...new Set(arr)]; -const union = (...arr) => unique([].concat(...arr)); - -compact(["foo", 0]); -unique(["foo", "foo"]); -union(["foo"], ["bar"], ["foo"]); -``` +Welcome to the frontend best practices guide! Elevate your web development skills with this comprehensive collection of tips and techniques. From responsive design to performance optimization, discover key principles for creating robust and user-friendly interfaces. Whether you're a seasoned developer or just starting, this guide has something valuable for everyone. \ No newline at end of file