前端参考指南

来源:转载


HTML
语义

HTML5为我们提供了大量的语义元素,旨在精准地描述内容。确保你受益于其丰富的词汇。


<!-- bad -->
<div>
<div>
<div>
<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>
<!-- bad --><div><div><div><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>

确保您理解您正在使用的语义元素。以错误的方式使用语义元素比不使用更糟糕。


<!-- bad -->
<h1>
<figure>
<img alt=Company src=logo.png>
</figure>
</h1><!-- good -->
<h1>
<img alt=Company src=logo.png>
</h1>
<!-- bad --><h1><figure><img alt=Company src=logo.png></figure></h1><!-- good --><h1><img alt=Company src=logo.png></h1>
简洁

保持代码简洁。忘记旧的XHTML习惯。


<!-- 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 [email protected] 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 [email protected] required>
</label>
<script src=main.js></script>
</html>
<!-- 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 [email protected] 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 [email protected] required></label><script src=main.js></script></html>
可访问性

可访问性不应该是一个事后的想法。你不必成为一位WCAG专家来提升你的网站,你可以立即开始修复这些小问题,它将产生巨大的改善,如:

学会正确使用alt属性
确保你的链接和按钮等都很好地标记(没有<div class =button>这种暴行)
不要完全依赖颜色来传达信息
显式地给表单控件加标签

<!-- bad -->
<h1><img src="logo.png"></h1><!-- good -->
<h1><img src="logo.png"></h1>
<!-- bad --><h1><img src="logo.png"></h1><!-- good --><h1><img src="logo.png"></h1>
语言

虽然定义语言和字符编码是可选的,但推荐在文档级别声明它们,即使它们已经在HTTP请求头部已经指定。字符编码优先使用utf – 8。


<!-- bad -->
<!doctype html>
<title>Hello, world.</title><!-- good -->
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<title>Hello, world.</title>
</html>
<!-- bad --><!doctype html><title>Hello, world.</title><!-- good --><!doctype html><html lang=en><meta charset=utf-8><title>Hello, world.</title></html>
性能

除非有一个合理的理由在内容之前加载脚本,否则请不要把它放在前面阻止页面的渲染。如果您的样式表很大,分离出初始化时必须的样式,并在一个独立样式表中延迟加载其它部分。两次HTTP请求显着低于一次,但感知速度是最重要的因素。


<!-- 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>
<!-- 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
分号

技术上来讲,分号在CSS里充当一个分隔符,但请把它当作一个终结符。


/* bad */
div {
color: red
}/* good */
div {
color: red;
}
/* bad */div {color: red}/* good */div {color: red;}
盒模型

盒模型对整个文档应该是相同的。虽然全局样式 * { box-sizing:border-box;} 很好,但不要在特定元素改变默认的盒模型(如果你可以避免这么做)。


/* bad */
div {
width: 100%;
padding: 10px;
box-sizing: border-box;
}/* good */
div {
padding: 10px;
}
/* bad */div {width: 100%;padding: 10px;box-sizing: border-box;}/* good */div {padding: 10px;}

不要改变元素的默认行为(如果你可以避免这么做)。尽量保持元素在普通的文档流中。例如,删除图像下面的空白,不应该改变其默认显示:


/* bad */
img {
display: block;
}/* good */
img {
vertical-align: middle;
}
/* bad */img {display: block;}/* good */img {vertical-align: middle;}

同样的,不要让一个元素脱离文档流(如果你可以避免这么做)。


/* bad */
div {
width: 100px;
position: absolute;
right: 0;
}/* good */
div {
width: 100px;
margin-left: auto;
}
/* bad */div {width: 100px;position: absolute;right: 0;}/* good */div {width: 100px;margin-left: auto;}
位置

有很多方法可以在CSS中定位元素,但尝试限制自己使用下面的属性/值。优先顺序如下:



display: block;
display: flex;
position: relative;
position: sticky;
position: absolute;
position: fixed;
display: block;display: flex;position: relative;position: sticky;position: absolute;position: fixed;
选择器

减少紧耦合的DOM选择器。当你的选择器超过3个结构伪类、后代或兄弟的组合,考虑添加一个class到你需要匹配的元素上。


/* bad */
div:first-of-type :last-child > p ~ */* good */
div:first-of-type .info
/* bad */div:first-of-type :last-child > p ~ */* good */div:first-of-type .info

避免在不必要的时候重载你的选择器。


/* bad */
img[src$=svg], ul > li:first-child {
opacity: 0;
}/* good */
[src$=svg], ul > :first-child {
opacity: 0;
}
/* bad */img[src$=svg], ul > li:first-child {opacity: 0;}/* good */[src$=svg], ul > :first-child {opacity: 0;}
特性

不要让选择器难以覆盖。减少使用 id 和避免 !important。


/* bad */
.bar {
color: green !important;
}
.foo {
color: red;
}/* good */
.foo.bar {
color: green;
}
.foo {
color: red;
}
/* bad */.bar {color: green !important;}.foo {color: red;}/* good */.foo.bar {color: green;}.foo {color: red;}
覆盖

覆盖样式让选择器和调试变得不易使用。尽可能避免它。


/* bad */
li {
visibility: hidden;
}
li:first-child {
visibility: visible;
}/* good */
li + li {
visibility: hidden;
}
/* bad */li {visibility: hidden;}li:first-child {visibility: visible;}/* good */li + li {visibility: hidden;}
继承

在可以继承的情况下,不要重复样式声明,。


/* bad */
div h1, div p {
text-shadow: 0 1px 0 #fff;
}/* good */
div {
text-shadow: 0 1px 0 #fff;
}
/* bad */div h1, div p {text-shadow: 0 1px 0 #fff;}/* good */div {text-shadow: 0 1px 0 #fff;}
简洁

保持代码简洁。使用简写属性,避免在不需要时使用多个属性。


/* 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;
}
/* 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;}
语言

优先使用英文而不是数学公式


/* bad */
:nth-child(2n + 1) {
transform: rotate(360deg);
}/* good */
:nth-child(odd) {
transform: rotate(1turn);
}
/* bad */:nth-child(2n + 1) {transform: rotate(360deg);}/* good */:nth-child(odd) {transform: rotate(1turn);}
浏览器引擎前缀

积极删除过时的浏览器引擎前缀。如果你需要使用它们,请在标准属性前插入。


/* 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;
}
/* 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;}
动画

优先使用过渡,而不是动画。避免对 opacity 和 transform 以外的属性使用动画。


/* bad */
div:hover {
animation: move 1s forwards;
}
@keyframes move {
100% {
margin-left: 100px;
}
}/* good */
div:hover {
transition: 1s;
transform: translateX(100px);
}
/* bad */div:hover {animation: move 1s forwards;}@keyframes move {100% {margin-left: 100px;}}/* good */div:hover {transition: 1s;transform: translateX(100px);}
单位

在可以的情况下,使用没有单位的值。在你使用相对单位时优先 rem 。优先使用秒而不是毫秒。


/* 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;
}
/* 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;}
颜色

如果你需要透明效果,请使用rgba。否则,总是使用十六进制格式。


/* bad */
div {
color: hsl(103, 54%, 43%);
}/* good */
div {
color: #5a3;
}
/* bad */div {color: hsl(103, 54%, 43%);}/* good */div {color: #5a3;}
绘图

当资源可以轻易地通过CSS实现时,避免HTTP请求。


/* bad */
div::before {
content: url(white-circle.svg);
}/* good */
div::before {
content: "";
display: block;
width: 20px;
height: 20px;
border-radius: 50%;
background: #fff;
}
/* bad */div::before {content: url(white-circle.svg);}/* good */div::before {content: "";display: block;width: 20px;height: 20px;border-radius: 50%;background: #fff;}
Hacks

不要使用它们。


/* bad */
div {
// position: relative;
transform: translateZ(0);
}/* good */
div {
/* position: relative; */
will-change: transform;
}
/* bad */div {// position: relative;transform: translateZ(0);}/* good */div {/* position: relative; */will-change: transform;}
JavaScript
性能

可读性,正确性和可表达性优先于性能。JavaScript基本上永远不会成为你的性能瓶颈。优化图像压缩、网络访问和DOM渲染。如果你仅记得本文的一条原则,记住这条。


// 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);
// 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);}// goodconst arr = [1, 2, 3, 4];const isEven = n => n % 2 == 0;const square = n => n * n;const result = arr.filter(isEven).map(square);
无污染

尽量保持你的函数干净。所有函数最好无副作用,不使用外部数据,返回新对象而不是改变现有的对象。


// 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" }
// badconst merge = (target, ...sources) => Object.assign(target, ...sources);merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" }// goodconst merge = (...sources) => Object.assign({}, ...sources);merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" }
原生

尽可能地依靠原生方法。


// bad
const toArray = obj => [].slice.call(obj);// good
const toArray = (() =>
Array.from ? Array.from : obj => [].slice.call(obj)
)();
// badconst toArray = obj => [].slice.call(obj);// goodconst toArray = (() =>Array.from ? Array.from : obj => [].slice.call(obj))();
强制转换

当有必要时,拥抱隐式强制转换。否则避免它。不要盲目使用。


// bad
if (x === undefined || x === null) { ... }// good
if (x == undefined) { ... }
// badif (x === undefined || x === null) { ... }// goodif (x == undefined) { ... }
循环

当强迫使用可变的对象时,不要使用循环。依靠 array.prototype 中的方法。


// 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
// badconst sum = arr => {var sum = 0;var i = -1;for (;arr[++i];) {sum += arr[i];}return sum;};sum([1, 2, 3]); // => 6// goodconst sum = arr =>arr.reduce((x, y) => x + y);sum([1, 2, 3]); // => 6

如果你不能,或者使用 array.prototype 方法很虐心。使用递归。


// 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);
// badconst createDivs = howMany => {while (howMany--) {document.body.insertAdjacentHTML("beforeend", "<div></div>");}};createDivs(5);// badconst createDivs = howMany =>[...Array(howMany)].forEach(() =>document.body.insertAdjacentHTML("beforeend", "<div></div>"));createDivs(5);// goodconst createDivs = howMany => {if (!howMany) return;document.body.insertAdjacentHTML("beforeend", "<div></div>");return createDivs(howMany - 1);};createDivs(5);
Arguments

忘记 arguments 对象。rest 参数一直是一个更好的选择,因为:

它是命名的,所以它给你一个函数期望arguments的更好的做法
它是一个真正的数组,这使得它更容易使用。

// bad
const sortNumbers = () =>
Array.prototype.slice.call(arguments).sort();// good
const sortNumbers = (...numbers) => numbers.sort();
// badconst sortNumbers = () =>Array.prototype.slice.call(arguments).sort();// goodconst sortNumbers = (...numbers) => numbers.sort();
Apply

忘记 apply() 。使用 spread 操作符代替。


const greet = (first, last) => `Hi ${first} ${last}`;
const person = ["John", "Doe"];// bad
greet.apply(null, person);// good
greet(...person);
const greet = (first, last) => `Hi ${first} ${last}`;const person = ["John", "Doe"];// badgreet.apply(null, person);// goodgreet(...person);
Bind

当有惯用方法时,不要使用 bind() 。


// 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()}`;
}
}
// bad["foo", "bar"].forEach(func.bind(this));// good["foo", "bar"].forEach(func, this);// badconst person = {first: "John",last: "Doe",greet() {const full = function() {return `${this.first} ${this.last}`;}.bind(this);return `Hello ${full()}`;}}// goodconst person = {first: "John",last: "Doe",greet() {const full = () => `${this.first} ${this.last}`;return `Hello ${full()}`;}}
高阶函数

在不必要时,避免嵌套函数。


// bad
[1, 2, 3].map(num => String(num));// good
[1, 2, 3].map(String);
// bad[1, 2, 3].map(num => String(num));// good[1, 2, 3].map(String);
组合

避免多嵌套函数的调用。使用组合。


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
const plus1 = a => a + 1;const mult2 = a => a * 2;// badmult2(plus1(5)); // => 12// goodconst pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val);const addThenMult = pipeline(plus1, mult2);addThenMult(5); // => 12
缓存

缓存功能测试、大数据结构和任何昂贵的操作。


// bad
const contains = (arr, value) =>
Array.prototype.includes
? arr.includes(value)
: arr.some(el => el === value);
contains(["foo", "bar"], "baz"); // => true// good
const contains = (() =>
Array.prototype.includes
? (arr, value) => arr.includes(value)
: (arr, value) => arr.some(el => el === value)
)();
contains(["foo", "bar"], "baz"); // => true
// badconst contains = (arr, value) =>Array.prototype.includes? arr.includes(value): arr.some(el => el === value);contains(["foo", "bar"], "baz"); // => true// goodconst contains = (() =>Array.prototype.includes? (arr, value) => arr.includes(value): (arr, value) => arr.some(el => el === value))();contains(["foo", "bar"], "baz"); // => true
变量定义

优先const,再是let,然后是var。


// bad
var obj = {};
obj["foo" + "bar"] = "baz";// good
const obj = {
["foo" + "bar"]: "baz"
};
// badvar obj = {};obj["foo" + "bar"] = "baz";// goodconst obj = {["foo" + "bar"]: "baz"};
条件

优先使用立即执行函数表达式(IIFE和返回语句,而不是 if,else if 和 switch 语句


// 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";
})();
// badvar grade;if (result < 50)grade = "bad";else if (result < 90)grade = "good";elsegrade = "excellent";// goodconst grade = (() => {if (result < 50)return "bad";if (result < 90)return "good";return "excellent";})();
对象迭代

在允许的情况下避免使用 for…in


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));
const shared = { foo: "foo" };const obj = Object.create(shared, {bar: {value: "bar",enumerable: true}});// badfor (var prop in obj) {if (obj.hasOwnProperty(prop))console.log(prop);}// goodObject.keys(obj).forEach(prop => console.log(prop));
对象映射

当对象合法使用情况下,map 通常是一个更好的,更强大的选择。如果有疑问,请使用 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
// badconst me = {name: "Ben",age: 30};var meSize = Object.keys(me).length;meSize; // => 2me.country = "Belgium";meSize++;meSize; // => 3// goodconst me = new Map();me.set("name", "Ben");me.set("age", 30);me.size; // => 2me.set("country", "Belgium");me.size; // => 3
Curry(柯里化)

柯里局可能在其他语言有它的地位,但避免在 JavaScript 使用。它通过引入外来范式,且相关的用例极不寻常,使得您的代码更难阅读。


// bad
const sum = a => b => a + b;
sum(5)(3); // => 8// good
const sum = (a, b) => a + b;
sum(5, 3); // => 8
// badconst sum = a => b => a + b;sum(5)(3); // => 8// goodconst sum = (a, b) => a + b;sum(5, 3); // => 8
可读性

不要通过看似聪明的技巧来混淆代码的意图。


// 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);
// badfoo || doSomething();// goodif (!foo) doSomething();// badvoid function() { /* IIFE */ }();// good(function() { /* IIFE */ }());// badconst n = ~~3.14;// goodconst n = Math.floor(3.14);
代码重用

不要害怕创造大量小,高度可组合、可重用的函数。


// 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);
// badarr[arr.length - 1];// goodconst first = arr => arr[0];const last = arr => first(arr.slice(-1));last(arr);// badconst product = (a, b) => a * b;const triple = n => n * 3;// goodconst product = (a, b) => a * b;const triple = product.bind(null, 3);
依赖

减少依赖。第三方代码你不熟悉。不要仅仅为了使用一些很容易复制的方法而加载整个库:


// 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"]);
// badvar _ = require("underscore");_.compact(["foo", 0]));_.unique(["foo", "foo"]);_.union(["foo"], ["bar"], ["foo"]);// goodconst 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"]);

分享给朋友:
您可能感兴趣的文章:
随机阅读: