前端参考指南

作者:Jasmine - 2015年09月29日

HTML

语义

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

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

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

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

可访问性


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

学会正确使用alt属性

确保你的链接和按钮等都很好地标记(没有<div class =button>这种暴行)

不要完全依赖颜色来传达信息

显式地给表单控件加标签

<!-- bad -->
<h1><img alt="Logo" src="logo.png"></h1>
 
<!-- good -->
<h1><img alt="My Company, Inc." 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>

性能


除非有一个合理的理由在内容之前加载脚本,否则请不要把它放在前面阻止页面的渲染。如果您的样式表很大,分离出初始化时必须的样式,并在一个独立样式表中延迟加载其它部分。两次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>

CSS

分号


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

/* 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 */
img {
  display: block;
}
 
/* good */
img {
  vertical-align: middle;
}

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

/* 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;

选择器


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

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

特性


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

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

动画


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

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

颜色


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

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

Hacks


不要使用它们。

/* 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
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" }

原生


尽可能地依靠原生方法。

// bad
const toArray = obj => [].slice.call(obj);
 
// good
const toArray = (() =>
  Array.from ? Array.from : obj => [].slice.call(obj)
)();

强制转换


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

// bad
if (x === undefined || x === null) { ... }
 
// good
if (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

如果你不能,或者使用 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);

Arguments


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


它是命名的,所以它给你一个函数期望arguments的更好的做法

它是一个真正的数组,这使得它更容易使用。

// bad
const sortNumbers = () =>
  Array.prototype.slice.call(arguments).sort();
 
// good
const 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);

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
[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

缓存


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

// 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

变量定义


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

// bad
var obj = {};
obj["foo" + "bar"] = "baz";
 
// good
const 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";
})();

对象迭代


在允许的情况下避免使用 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));


本文作者: Jasmine

本文链接: https://www.jianbaizhan.com/article/306

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!


 请勿发布不友善或者负能量的内容。审查将对发布广告等违规信息进行处罚!