http://viv3k.com/blog/wp-content/uploads/2016/05/frontend-guidelines.html
HTML
Semantics
HTML5 provides us with lots of semantic elements aimed to describe precisely the content. Make sure you benefit from its rich vocabulary.
<!-- bad --> <div id="main"> <div class="article"> <div class="header"> <h1>Blog post</h1> <p>Published: <span>21st Feb, 2015</span></p> </div> <p>…</p> </div> </div> <!-- good --> <main> <article> <header> <h1>Blog post</h1> <p>Published: <time datetime="2015-02-21">21st Feb, 2015</time></p> </header> <p>…</p> </article> </main>
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.
<!-- bad --> <h1> <figure> <img alt=Company src=logo.png> </figure> </h1> <!-- good --> <h1> <img alt=Company src=logo.png> </h1>
Brevity
Keep your code terse. Forget about your old XHTML habits.
<!-- bad --> <!doctype html> <html lang=en> <head> <meta http-equiv=Content-Type content="text/html; charset=utf-8" /> <title>Contact</title> <link rel=stylesheet href=style.css type=text/css /> </head> <body> <h1>Contact me</h1> <label> Email address: <input type=email placeholder=you@email.com required=required /> </label> <script src=main.js type=text/javascript></script> </body> </html> <!-- good --> <!doctype html> <html lang=en> <meta charset=utf-8> <title>Contact</title> <link rel=stylesheet href=style.css> <h1>Contact me</h1> <label> Email address: <input type=email placeholder=you@email.com required> </label> <script src=main.js></script> </html>
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 <div class=button> atrocities)
not relying exclusively on colors to communicate information
explicitly labelling form controls
<!-- bad --> <h1><img alt="Logo" src="logo.png"></h1> <!-- good --> <h1><img alt="My Company, Inc." src="logo.png"></h1>
Language
While defining the language and character encoding is optional, it’s recommended to always declare both at document level, even if they’re specified in your HTTP headers. Favor UTF-8 over any other character encoding.
<!-- bad --> <!doctype html> <title>Hello, world.</title> <!-- good --> <!doctype html> <html lang=en> <meta charset=utf-8> <title>Hello, world.</title> </html>
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.
<!-- bad --> <!doctype html> <meta charset=utf-8> <script src=analytics.js></script> <title>Hello, world.</title> <p>...</p> <!-- good --> <!doctype html> <meta charset=utf-8> <title>Hello, world.</title> <p>...</p> <script src=analytics.js></script>
CSS
Semicolons
While the semicolon is technically a separator in CSS, always treat it as a terminator.
/* 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.
/* 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:
/* bad */ img { display: block; } /* good */ img { vertical-align: middle; }
Similarly, don’t take an element off the flow if you can avoid it.
/* 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 but try to restrict yourself to the properties/values below. By order of preference:
{ display: block; display: flex; position: relative; position: sticky; position: absolute; position: fixed; }
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.
/* bad */ div:first-of-type :last-child > p ~ * /* good */ div:first-of-type .info
Avoid overloading your selectors when you don’t need to.
/* 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.
/* 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.
/* bad */ li { visibility: hidden; } li:first-child { visibility: visible; } /* good */ li + li { visibility: hidden; }
Inheritance
Don’t duplicate style declarations that can be inherited.
/* 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.
/* 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.
/* 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.
/* 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.
/* 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.
/* 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.
/* bad */ div { color: hsl(103, 54%, 43%); } /* good */ div { color: #5a3; }
Drawing
Avoid HTTP requests when the resources are easily replicable with 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.
/* 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// bad const createDivs = howMany => { while (howMany--) { document.body.insertAdjacentHTML("beforeend", "<div></div>"); } }; createDivs(5); // bad const createDivs = howMany => [...Array(howMany)].forEach(() => document.body.insertAdjacentHTML("beforeend", "<div></div>") ); createDivs(5); // good const createDivs = howMany => { if (!howMany) return; document.body.insertAdjacentHTML("beforeend", "<div></div>"); return createDivs(howMany - 1); }; createDivs(5);
Arguments
Forget about the arguments object. The rest parameter is always a better option because:
it’s named, so it gives you a better idea of the arguments the function is expecting
it’s a real array, which makes it easier to use.
// bad const sortNumbers = () => Array.prototype.slice.call(arguments).sort(); // good const sortNumbers = (...numbers) => numbers.sort();
Apply
Forget about apply(). Use the spread operator instead.
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.
// bad ["foo", "bar"].forEach(func.bind(this)); // good ["foo", "bar"].forEach(func, this); // 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.
// bad [1, 2, 3].map(num => String(num)); // good [1, 2, 3].map(String);
Composition
Avoid multiple nested function calls. Use composition instead.
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.
// 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.
// 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.
// 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.
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.
// 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.
// 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.
// bad foo || doSomething(); // good if (!foo) doSomething(); // bad void function() { /* IIFE */ }(); // good (function() { /* IIFE */ }()); // 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.
// bad arr[arr.length - 1]; // good const first = arr => arr[0]; const last = arr => first(arr.slice(-1)); last(arr); // 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:
// 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 => [...Set(arr)]; const union = (...arr) => unique([].concat(...arr)); compact(["foo", 0]); unique(["foo", "foo"]); union(["foo"], ["bar"], ["foo"]);
First and most importantly, learn how to write in pure JavaScript. Have an understanding of what libraries are built from.
tl;dr – Find an application you like to make, and remake it in every new library you want to learn.
I teach a lot of people to write in Javascript. And the thing I have noticed when they need to learn a second framework is that they always get stuck up on why the new language can’t do something their old one can.
I don’t think that is productive. So, after some serious trial and error, I figured out what I think is the best way to write in a new library.
Find a simple tool you enjoy building. Something that has the basics of a simple application. API support, data binding(or lack of), repeating elements, promises, etc.
Make sure you can build it in your first library with your eyes closed. When you can do that, try your hand at building the exact same tool in the new library.
Compare each step with a feature you are used to, and use google to help you find the best practices that compare to them in your new library.
In Angular, you keep JSON data and logical code in services, and make API calls from a factory. How would you structure that with Backbone? Would you keep your logic inside a model?
Good luck making yourself marketable and well rounded.
Throbbing Things in CSS
:CSS
.throb { border: 3px solid #555; height: 50px; width: 50px; -webkit-border-radius: 50%; -webkit-animation: pulsate 2s ease-out; -webkit-animation-iteration-count: infinite; opacity: 0; z-index: 999; } @-webkit-keyframes pulsate { 0% { -webkit-transform: scale(1.0, 1.0); opacity: 1.0; } 50% { -webkit-transform: scale(0.75, 0.75); opacity: 0.5; } 100% { -webkit-transform: scale(1.0, 1.0); opacity: 1.0; } }
:HTML
<div class="throb"></div>
Enable console.log messages only when a variable is set to true:
var debugMode = true; var debugLog = function(){ debugMode && console.log.apply( console, arguments ); }
Now in your code, you can insert any number of debug log messages, that will be visible only when the debugMode variable is set to true.
debugLog("Ops! Debug Mode is on and there's an error !");
debugLog
https://t.co/Ads4XKHTCV #Married #9thJan2015 #beautiful #Kerala #traditionalWedding http://t.co/DHPglYyGf7
— Vivek kuniyil (@kvivek4you) February 18, 2015
<div class=“box”>1</div> <div class=“box”>2</div> <div class=“box”>3</div>
Let’s say I want to output the innerHTML
value, and then delete each box from the DOM.
with getElementsByClassName
, we can easily do:
var boxes = document.getElementsByClassName(‘box’); for(var i=0; i<boxes.length; i++) { console.log(boxes[i].innerHTML); boxes[i].parentNode.removeChild(boxes[i]); }
Gotcha! This, sadly, will not work. The output:
1
3
ERROR
The reason is that when boxes[0]
(first box) is deleted, that node is also deleted from from the variable boxes
. So, the first element of boxes
is now the second box.
Now, since the array auto-updates itself, the way to do this is:
while(boxes.length) {
console.log(boxes[0].innerHTML);
boxes[0].parentNode.removeChild(boxes[0]);
}
I want to share a neat little trick with jQuery DOM creation.
I often see jQuery scripts create DOM elements like this:
var $elem = $('<div>' + text + '</div>');
// OR
var $elem = $("<div>").addClass('some-class').text("text content");
There is nothing wrong with the above methods, but you can actually pass in an object to extend the element being created like so:
var $elem = $('<div/>', {"class" : "some-class",
"attr" : "value",
"text" : "text content", // equivalent to .text()
"html" : "<h3>title</h3>", // equivalent to .html()
"click" : function() { } // click event
});
Using this method, you can create an DOM using a predefined object and stay away from nasty string concatenations.
Ahhh yes… So you just validated your awesome form and want to grab all the awesome errors for some awesome reason.
Just add a sprinkling of:
var validator = $("#awesomeForm").validate(); var errors = validator.errorList;
This will give you a list of awesome validator error objects that includes the error message and the actual awesome jquery element object.
You’re welcome 🙂
(I used “awesome” quite a bit)
After reading Addy Osmani’s book ‘JavaScript design patterns’ , I thought I would summarize some of the patterns I found useful and have been using in some projects.It is an awesome book and has a lot of useful information for JavaScript framework developers.
Module pattern
The Module pattern encapsulates “privacy”, state and organization using closures. Itprovides a way of wrapping a mix of public and private methods and variables. With this pattern, only a public API is returned, keeping everything else within the closure private.
var myNamespace = (function () { var myPrivateVar, myPrivateMethod; myPrivateVar = 0; myPrivateMethod = function( foo ) { console.log( foo ); }; return { myPublicVar: "foo", myPublicFunction: function( bar ) { myPrivateVar++; myPrivateMethod( bar ); } }; })();
Revealing Module pattern
The revealing module pattern is an updated version of the module pattern where all functions and variables are declared in the private scope and an anonymous object with pointers to the private functionality is returned.
var myRevealingModule = (function () { var privateVar = "this is private", publicVar = "this is public"; function privateFunction() { console.log( privateVar ); } function publicSetName( strName ) { privateVar = strName; } function publicGetName() { privateFunction(); } // Reveal public pointers to private functions and properties return { setName: publicSetName, greeting: publicVar, getName: publicGetName }; })();
Prototype inheritance
JavaScript doesn’t support the concept of classes but it does support special constructor functions that work with objects. Functions in JavaScript have a property called a prototype. When we call a JavaScript constructor to create an object, all the properties of the constructor’s prototype are then made available to the new object.
function Car(model, year) { this.model = model; this.year = year; } Car.prototype.toString = function() { return this.model + ", " + this.year; }; var suzuki= new Car("Maruti 800",1983);
Singleton pattern
In JavaScript, Singletons serve as a shared resource namespace. The singleton pattern is used to restrict instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
function init() { // Private methods and variables function privateMethod(){ console.log( "I am private" ); } var privateVariable = "Im private"; return { // Public methods and variables publicMethod: function () { console.log( "The public can see me!" ); }, publicProperty: "I am public", }; }; return { // Get the Singleton instance if one exists getInstance: function () { if ( !instance ) { instance = init(); } return instance; } }; })(); var singleA = mySingleton.getInstance(); console.log(singleA.publicMethod());
Mixin inheritance
In JavaScript, we can look at inheriting from Mixins as a means of collecting functionality through extension. Each new object we define has a prototype from which it can inherit further properties.
var Person = function( firstName, lastName){ this.firstName = firstName; this.lastName = lastname; } var clark = new Person("Clark", "Kent"); var Superhero = function(firstName,lastname, powers){ this.powers = powers; Person.call(this,firstName,lastName); }; SuperHero.prototype = Object.create(Person.prototype); var superMan = new Superhero( "Clark", "Kent", [ "flight", "strength" ]);
Facade pattern
This pattern provides a convenient higher-level interface to a larger body of code,hiding its true underlying complexity. jQuery uses facades for much of its API to simplify complex operations. An example is jQuery’s $(document).ready(..) method which internally, is powered by a method called bindReady() which performs some ofthe following, to simplify the job for us.
$(document).ready(function () { //... });
http://addyosmani.com/resources/essentialjsdesignpatterns/book/#designpatternsjavascript