前端指南 – HTML/CSS/Javascript[WEB前端]

  • 无规矩不成方圆,初学者一起来看看大神的经验。

HTML

语义

  • HTML5 为我们提供了许多语义元素,旨在精确描述内容。确保你受益于它丰富的词汇。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!-- 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>
  • 确保您了解正在使用的元素的语义。用错误的方式使用语义元素比保持中立更糟糕。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!-- bad -->
    <h1>
    <figure>
    <img alt=Company src=logo.png>
    </figure>
    </h1>

    <!-- good -->
    <h1>
    <img alt=Company src=logo.png>
    </h1>

简洁

  • 保持代码简洁。忘记你旧的XHTML习惯。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <!-- 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
  • 确保您的链接和按钮被标记为此类(无暴行)
  • 不完全依靠颜色来传达信息
  • 明确标记表单控件
    1
    2
    3
    4
    5
    <!-- bad -->
    <h1><img alt=Logo src=logo.png></h1>

    <!-- good -->
    <h1><img alt=Company src=logo.png></h1>

语言和字符编码

  • 虽然定义语言是可选的,但建议始终在根元素上声明它。
  • HTML 标准要求页面使用 UTF-8 字符编码。必须声明它,虽然可以在内容类型 HTTP 标头中声明它,但建议始终在文档级别声明它
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!-- bad -->
    <!doctype html>
    <title>Hello, world.</title>

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

性能

  • 除非在内容之前加载脚本有正当理由,否则不要阻止页面的呈现。如果样式表很重,请隔离最初绝对必需的样式,并推迟在单独的样式表中加载辅助声明。两个 HTTP 请求明显慢于一个请求,但速度感知是最重要的因素。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!-- 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 中的分隔符,但始终将其视为终止符。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* bad */
    div {
    color: red
    }

    /* good */
    div {
    color: red;
    }

箱模型

  • 理想情况下,整个文档的框模型应相同。全局是好的,但如果可以避免,则不要更改特定元素上的默认框模型。* { box-sizing: border-box; }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* bad */
    div {
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
    }

    /* good */
    div {
    padding: 10px;
    }

Flow

  • 如果可以避免元素的默认行为,请不要更改它。尽可能多地将元素保留在自然文档流中。例如,删除图像下方的空白不应使您更改其默认显示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* bad */
    img {
    display: block;
    }

    /* good */
    img {
    vertical-align: middle;
    }
  • 同样,如果可以避免元素,请不要从流中取下元素。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* bad */
    div {
    width: 100px;
    position: absolute;
    right: 0;
    }

    /* good */
    div {
    width: 100px;
    margin-left: auto;
    }

定位

  • 有许多方法可以定位 CSS 中的元素。青睐现代布局规范(如 Flexbox 和 Grid),并避免从普通文档流中删除元素,例如使用 。position: absolute

选择

  • 最小化与 DOM 紧密耦合的选择器。考虑在选择器超过 3 个结构伪类、后代或同级组合器时,将类添加到要匹配的元素。

    1
    2
    3
    4
    5
    /* bad */
    div:first-of-type :last-child > p ~ *

    /* good */
    div:first-of-type .info
  • 避免在不需要时使选择器过载。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* bad */
    img[src$=svg], ul > li:first-child {
    opacity: 0;
    }

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

特 异性

  • 不要使值和选择器难以覆盖。尽量减少 的 和 的 使用。id!important
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /* bad */
    .bar {
    color: green !important;
    }
    .foo {
    color: red;
    }

    /* good */
    .foo.bar {
    color: green;
    }
    .foo {
    color: red;
    }

重写

  • 重写样式使选择器和调试更加困难。尽可能避免。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* bad */
    li {
    visibility: hidden;
    }
    li:first-child {
    visibility: visible;
    }

    /* good */
    li + li {
    visibility: hidden;
    }

继承

  • 不要复制可以继承的样式声明。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* bad */
    div h1, div p {
    text-shadow: 0 1px 0 #fff;
    }

    /* good */
    div {
    text-shadow: 0 1px 0 #fff;
    }

简洁

  • 保持代码简洁。使用速记属性,避免在不需要时使用多个属性。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /* 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;
    }

语言

  • 比起数学,更喜欢英语。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* bad */
    :nth-child(2n + 1) {
    transform: rotate(360deg);
    }

    /* good */
    :nth-child(odd) {
    transform: rotate(1turn);
    }

供应商前缀

  • 积极终止过时的供应商前缀。如果需要使用它们,请在标准属性之前插入它们。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /* 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;
    }

动画

  • 有利于转换而不是动画。避免对 和 以外的其他属性进行动画处理。opacitytransform
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /* bad */
    div:hover {
    animation: move 1s forwards;
    }
    @keyframes move {
    100% {
    margin-left: 100px;
    }
    }

    /* good */
    div:hover {
    transition: 1s;
    transform: translateX(100px);
    }

单位

  • 可以时使用无单位值。如果您使用相对单位,则有利。首选秒数而不是毫秒。rem
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /* 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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* bad */
    div {
    color: hsl(103, 54%, 43%);
    }

    /* good */
    div {
    color: #5a3;
    }

绘图

  • 当资源易于使用 CSS 进行复制时,请避免 HTTP 请求。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /* bad */
    div::before {
    content: url(white-circle.svg);
    }

    /* good */
    div::before {
    content: "";
    display: block;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #fff;
    }

黑客

  • 不要使用它们。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /* bad */
    div {
    // position: relative;
    transform: translateZ(0);
    }

    /* good */
    div {
    /* position: relative; */
    will-change: transform;
    }

Javascript

性能

  • 比起性能,更有利于可读性、正确性和表达性。JavaScript 基本上永远不会成为您的性能瓶颈。而是优化图像压缩、网络访问和 DOM 回流等内容。如果您只记住本文档中的一个准则,请选择此准则。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 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);

无 国籍

  • 尽量保持功能纯净。理想情况下,所有函数都不应产生副作用,不使用外部数据并返回新对象,而不是突变现有对象。
    1
    2
    3
    4
    5
    6
    7
    // 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" }

当地人

  • 尽可能依赖本机方法。
    1
    2
    3
    4
    5
    6
    7
    // bad
    const toArray = obj => [].slice.call(obj);

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

强制

  • 在有意义的时候接受隐含的胁迫。否则避免。不要货物崇拜。
    1
    2
    3
    4
    5
    // bad
    if (x === undefined || x === null) { ... }

    // good
    if (x == undefined) { ... }

循环

  • 不要使用循环,因为它们会强制您使用可变对象。依赖于方法。array.prototype

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // 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
  • 它的名字,所以它给你一个更好的想法,函数期待的参数
  • 它是一个真正的数组,这使得它更容易使用。
    1
    2
    3
    4
    5
    6
    // bad
    const sortNumbers = () =>
    Array.prototype.slice.call(arguments).sort();

    // good
    const sortNumbers = (...numbers) => numbers.sort();

应用

  • 忘记 。改用点差运算符。apply()
    1
    2
    3
    4
    5
    6
    7
    8
    const greet = (first, last) => `Hi ${first} ${last}`;
    const person = ["John", "Doe"];

    // bad
    greet.apply(null, person);

    // good
    greet(...person);

绑定

  • 当有一个更惯用的方法时,不要这样做。bind()
    1
    2
    3
    4
    5
    // bad
    ["foo", "bar"].forEach(func.bind(this));

    // good
    ["foo", "bar"].forEach(func, this);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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()}`;
}
}

高阶函数

  • 不必嵌套函数。
    1
    2
    3
    4
    5
    // bad
    [1, 2, 3].map(num => String(num));

    // good
    [1, 2, 3].map(String);

组成

  • 避免多次嵌套函数调用。改用合成。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

缓存

  • 缓存功能测试、大型数据结构和任何昂贵的操作。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 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

变量

  • 一遍又一遍地偏袒。constletletvar
    1
    2
    3
    4
    5
    6
    7
    // bad
    var me = new Map();
    me.set("name", "Ben").set("country", "Belgium");

    // good
    const me = new Map();
    me.set("name", "Ben").set("country", "Belgium");

条件

  • 如果(否则)和切换语句,则支持 IIFE 并返回语句。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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));

对象作为地图

  • 虽然对象具有合法的用例,但地图通常是更好、更强大的选择。当有疑问时,请使用 。Map
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 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

咖喱

  • 对于许多开发人员来说,咖喱是一种强大但外国的模式。不要滥用它,因为它适当的用例是相当不寻常的。
    1
    2
    3
    4
    5
    6
    7
    // bad
    const sum = a => b => a + b;
    sum(5)(3); // => 8

    // good
    const sum = (a, b) => a + b;
    sum(5, 3); // => 8

可读性

  • 不要使用看似聪明的技巧来混淆代码的意图。
    1
    2
    3
    4
    5
    // bad
    foo || doSomething();

    // good
    if (!foo) doSomething();
1
2
3
4
5
// bad
void function() { /* IIFE */ }();

// good
(function() { /* IIFE */ }());
1
2
3
4
5
// bad
const n = ~~3.14;

// good
const n = Math.floor(3.14);

代码重用

  • 不要害怕创建大量小型、高度可组合和可重用的功能。
    1
    2
    3
    4
    5
    6
    7
    // bad
    arr[arr.length - 1];

    // good
    const first = arr => arr[0];
    const last = arr => first(arr.slice(-1));
    last(arr);
1
2
3
4
5
6
7
// 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);

依赖

  • 最小化依赖项。第三方是你不知道的代码。不要只加载整个库,只需几种方法即可轻松复制:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 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"]);