酷思纬哲研发部 - 前端 编码规范

1,246 阅读20分钟

酷思纬哲研发部 - 前端 编码规范

这是一份旨在增强团队的开发协作,提高代码质量和打造开发基石的编码风格规范,其中包含了 HTML, JavaScript 和 CSS/SCSS 这几个部分。我们知道,当一个团队开始指定并实行编码规范的话,错误就会变得更加显而易见。如果一段特定的代码不符合规范的话,它有可能只是代码风格错误,而也有可能会是 bug。早期指定规范就使得代码审核得以更好的开展,并且可以更精确的地定位到错误。只要开发者们能够保证源代码源文件都严格遵循规范,那接下去所使用的混淆、压缩和编译工具则可投其所好不尽相同。希望各位同事严格以前端规范文档要求自己。

** 最新修改于 2019年06月26日 10:30 **

参考原文:Web Styleguide – Style guide to harmonize HTML, Javascript and CSS / SASS coding style


一般规范

以下章节列举了一些可应用在 HTML, JavaScript 和 CSS/SCSS 上的通用规则。


文件/资源命名

在 web 项目中,所有的文件名应该都遵循同一命名约定。以可读性而言,减号(-)是用来分隔文件名的不二之选。同时它也是常见的 URL 分隔符(i.e. //example.com/blog/my-blog-entry or //s.example.com/images/big-black-background.jpg),所以理所当然的,减号应该也是用来分隔资源名称的好选择。 请确保文件命名总是以字母开头而不是数字。而以特殊字符开头命名的文件,一般都有特殊的含义与用处(i.e. _ __ )。 资源的字母名称必须全为小写,这是因为在某些对大小写字母敏感的操作系统中,当文件通过工具压缩混淆后,或者人为修改过后,大小写不同而导致引用文件不同的错误,很难被发现。 还有一些情况下,需要对文件增加前后缀或特定的扩展名(比如 .min.js, .min.css),抑或一串前缀(比如 3fa89b.main.min.css)。这种情况下,建议使用点分隔符来区分这些在文件名中带有清晰意义的元数据。

不推荐

MyScript.js
myCamelCaseName.css
i_love_underscores.html
1001-scripts.js
my-file-min.css

推荐

my-script.js
my-camel-case-name.css
i-love-underscores.html
thousand-and-one-scripts.js
my-file.min.css

协议

不要指定引入资源所带的具体协议。

当引入图片或其他媒体文件,还有样式和脚本时,URLs 所指向的具体路径,不要指定协议部分(http:, https:),除非这两者协议都不可用。

不指定协议使得 URL 从绝对的获取路径转变为相对的,在请求资源协议无法确定时非常好用,而且还能为文件大小节省几个字节。

不推荐

<script src="http://cdn.com/foundation.min.js"></script>
<script src="https://cdn.com/foundation.min.js"></script>

推荐

<script src="//cdn.com/foundation.min.js"></script>

不推荐

.example {
    background: url(http://static.example.com/images/bg.jpg);
    background: url(https://static.example.com/images/bg.jpg);
}

推荐

.example {
    background: url(//static.example.com/images/bg.jpg);
}

文本缩进

一次缩进个空格。习惯用tab键可以使用IDE自动转换成空格。

<ul>
    <li>Fantastic</li>
    <li>Great</li>
    <li>
        <a href="#">Test</a>
    </li>
</ul>
@media screen and (min-width: 1100px) {
    body {
        font-size: 100%;
    }
}
(function(){
    var x = 10;
 
    function y(a, b) {
        return {
            result: (a + b) * x
        }
 
    }
}());

注释

注释是你自己与你的小伙伴们了解代码写法和目的的唯一途径。特别是在写一些看似琐碎的无关紧要的代码时,由于记忆点不深刻,注释就变得尤为重要了。 注释也能让你和同事们更加快捷了解代码块的模块功能


代码检查/代码审查/代码提交/代码更新

  • 代码检查 - 对于比较宽松自由的编程语言来说,严格遵循编码规范和格式化风格指南就显得极为重要。
  • 代码审查 - 养成审查代码的习惯,对个人的发展有更好的帮助。
  • 代码更新/提交 - 永远记住一个原则:先更新最新代码再提交本地代码,确保你提交的版本的最新的版本。

HTML规范


文档类型

推荐使用 HTML5 的文档类型申明: <!DOCTYPE html>. (建议使用 text/html 格式的 HTML。避免使用 XHTML。XHTML 以及它的属性,比如 application/xhtml+xml 在浏览器中的应用支持与优化空间都十分有限)。

HTML 中最好不要将无内容元素的标签闭合,例如:使用 <br> 而非 <br />.(i.e. area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr)


HTML 验证

一般情况下,建议使用能通过标准规范验证的 HTML 代码,除非在性能优化和控制文件大小上不得不做出让步。 规范化的 HTML 是显现技术要求与局限的显著质量基线,它促进了 HTML 被更好地运用。

不推荐

<title>Test</title>
<article>This is only a test.

推荐

<!DOCTYPE html>
<meta charset="utf-8">
<title>Test</title>
<article>This is only a test.</article>

省略可选标签

HTML5 规范中规定了 HTML 标签是可以省略的。但从可读性来说,在开发的源文件中最好不要这样做,因为省略标签可能会导致一些问题。

省略一些可选的标签确实使得页面大小减少,这很有用,尤其是对于一些大型网站来说。为了达到这一目的,我们可以在开发后期对页面进行压缩处理,在这个环节中这些可选的标签完全就可以省略掉了。


脚本加载

出于性能考虑,脚本异步加载很关键。一段脚本放置在 <head> 内,比如 <script src="main.js"></script>,其加载会一直阻塞 DOM 解析,直至它完全地加载和执行完毕。这会造成页面显示的延迟。特别是一些重量级的脚本,对用户体验来说那真是一个巨大的影响。 异步加载脚本可缓解这种性能影响。如果只需兼容 IE10+,可将 HTML5 的 async 属性加至脚本中,它可防止阻塞 DOM 的解析,甚至你可以将脚本引用写在 <head> 里也没有影响。

在所有浏览器中,推荐

<html>
<head>
    <link rel="stylesheet" href="main.css">
</head>
<body>
    <!-- body goes here -->

    <script src="main.js" async></script>
</body>
</html>

现在浏览器中,推荐

<html>
<head>
    <link rel="stylesheet" href="main.css">
    <script src="main.js" async></script>
</head>
<body>
    <!-- body goes here -->
</body>
</html>

语义化

根据元素(有时被错误地称作“标签”)其被创造出来时的初始意义来使用它。打个比方,用 header 元素来定义头部标题,p 元素来定义文字段落,用 a 元素来定义链接锚点,等等。

有根据有目的地使用 HTML 元素,对于可访问性、代码重用、代码效率来说意义重大。书写html代码时应避免通篇div元素。

推荐

<header>
    <h1>My page title</h1>
</header>
 
<nav class="top-navigation">
    <ul>
        <li class="nav-item"><a href="#home">Home</a></li>
        <li class="nav-item"><a href="#news">News</a></li>
        <li class="nav-item"><a href="#about">About</a></li>
    </ul>
</nav>
 
<main class="news-page" role="main">
    <section class="page-section news">
        <header>
            <h2 class="title">All news articles</h2>
        </header>
 
        <article class="news-article">
            <header>
                <div class="article-title">Good article</div>
                <small class="intro">Introduction sub-title</small>
            </header>
 
            <div class="content">
                <p>This is a good example for HTML semantics</p>
            </div>
            <aside class="article-side-notes">
                <p>I think I'm more on the side and should not receive the main credits</p>
            </aside>
            <footer class="article-foot-notes">
                <p>This article was created by David <time datetime="2014-01-01 00:00" class="time">1 month ago</time></p>
            </footer>
        </article>
 
        <footer class="section-footer">
            <p>Related sections: Events, Public holidays</p>
        </footer>
    </section>
</main>
 
<footer class="page-footer">
    Copyright 2014
</footer>

关注点分离

理解 web 中如何和为何区分不同的关注点,这很重要。这里的关注点主要指的是:信息(HTML 结构)、外观(CSS)和行为(JavaScript)。为了使它们成为可维护的干净整洁的代码,我们要尽可能的将它们分离开来。

严格地保证结构、表现、行为三者分离,并尽量使三者之间没有太多的交互和联系。

就是说,尽量在文档和模板中只包含结构性的 HTML;而将所有表现代码,移入样式表中;将所有动作行为,移入脚本之中。

在此之外,为使得它们之间的联系尽可能的小,在文档和模板中也尽量少地引入样式和脚本文件。

清晰的分层意味着,实际开发项目中应尽量参照一下标准:

  • 不使用超过一到两张样式表(i.e. main.css, vendor.css)
  • 不使用超过一到两个脚本(学会用合并脚本)
  • 不使用行内样式(<style>.no-good {}</style>
  • 不在元素上使用 style 属性(<hr style="border-top: 5px solid black">
  • 不使用行内脚本(<script>alert('no good')</script>
  • 不使用表象元素(i.e. <b>, <u>, <center>, <font>, <b>
  • 不使用表象 class 名(i.e. red, left, center)

不推荐

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="base.css">
    <link rel="stylesheet" href="grid.css">
    <link rel="stylesheet" href="type.css">
    <link rel="stylesheet" href="modules/teaser.css">
</head>
<body>
    <h1 style="font-size: 3rem"></h1>
    <b>I'm a subtitle and I'm bold!</b>
    <center>Dare you center me!</center>
    <script>
        alert('Just dont...');
    </script>
    <div class="red">I'm important!</div>
</body>
</html>

推荐

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="main.css">
</head>
<body>
    <h1 class="title"></h1>
    <div class="sub-title">I'm a subtitle and I'm bold!</div>
    <span class="comment">Dare you center me!</span>
     what you want to do with it -->
    <div class="important">I'm important!</div>
 
    <script async src="main.js"></script>
</body>
</html>

HTML 内容至上

不要让非内容信息污染了你的 HTML。现在貌似有一种倾向:通过 HTML 来解决设计问题,这是显然是不对的。HTML 就应该只关注内容。

HTML 标签的目的,就是为了不断地展示内容信息。 * 不要引入一些特定的 HTML 结构来解决一些视觉设计问题 * 不要将 img 元素当做专门用来做视觉设计的元素 以下例子展示了误将 HTML 用来解决设计问题的这两种情况:

不推荐

<span class="text-box">
    <span class="square"></span>
    See the square next to me?
</span>
.text-box > .square {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    background-color: red;
}

推荐

<span class="text-box">
    See the square next to me?
</span>
.text-box::before {
    content: "";
    display: inline-block;
    width: 1rem;
    height: 1rem;
    background-color: red;
}

ID 和锚点

通常一个比较好的做法是将页面内所有的头部标题元素都加上 ID. 这样做,页面 URL 的 hash 中带上对应的 ID 名称,即形成描点,方便跳转至对应元素所处位置。

打个比方,当你在浏览器中输入 URL http://your-site.com/about#best-practices,浏览器将定位至以下 H3 上。

<h3 id="best-practices">Best practices</h3>

格式化规则

在每一个块状元素,列表元素和表格元素后,加上一新空白行,并对其子孙元素进行缩进。内联元素写在一行内,块状元素还有列表和表格要另起一行。

(如果由于换行的空格引发了不可预计的问题,那将所有元素并入一行也是可以接受的,格式警告总好过错误警告)。

推荐

<blockquote>
    <p><em>Space</em>, the final frontier.</p>
</blockquote>
 
<ul>
    <li>Moe</li>
    <li>Larry</li>
    <li>Curly</li>
</ul>
 
<table>
    <thead>
        <tr>
            <th scope="col">Income</th>
            <th scope="col">Taxes</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>$ 5.00</td>
            <td>$ 4.50</td>
        </tr>
    </tbody>
</table>

HTML 引号

使用双引号(" ") 而不是单引号(' ') 。

不推荐

<div class='news-article'></div>

推荐

<div class="news-article"></div>

CSS 规范


ID and class naming

ID和class(类)名总是使用可以反应元素目的和用途的名称,或其他通用名称。代替表象和晦涩难懂的名称。

应该首选具体和反映元素目的的名称,因为这些是最可以理解的,而且发生变化的可能性最小。

通用名称只是多个元素的备用名,他们兄弟元素之间是一样的,没有特别意义。 区分他们,使他们具有特殊意义,通常需要为“帮手”。

尽管class(类)名和ID 的语义化对于计算机解析来说没有什么实际的意义, 语义化的名称 通常是正确的选择,因为它们所代表的信息含义,不包含表现的限制。

不推荐

.fw-800 {
    font-weight: 800;
}
 
.red {
    color: red;
}

推荐

.heavy {
    font-weight: 800;
}
 
.important {
    color: red;
}

合理的避免使用ID

一般情况下ID不应该被应用于样式。 ID的样式不能被复用并且每个页面中你只能使用一次ID。 使用ID唯一有效的是确定网页或整个站点中的位置。 尽管如此,你应该始终考虑使用class,而不是id,除非只使用一次。

不推荐

#content .title {
    font-size: 2em;
}

推荐

.content .title {
    font-size: 2em;
}

另一个反对使用ID的观点是含有ID选择器权重很高。 一个只包含一个ID选择器权重高于包含1000个class(类)名的选择器,这使得它很奇怪。

// 这个选择器权重高于下面的选择器
#content .title {
    color: red;
}
 
// than this selector!
html body div.content.news-content .title.content-title.important {
    color: blue;
}

CSS选择器中避免标签名

当构建选择器时应该使用清晰, 准确和有语义的class(类)名。不要使用标签选择器。 如果你只关心你的class(类)名,而不是你的代码元素,这样会更容易维护。

从分离的角度考虑,在表现层中不应该分配html标记/语义。 它可能是一个有序列表需要被改成一个无序列表,或者一个div将被转换成article。 如果你只使用具有实际意义的class(类)名, 并且不使用元素选择器,那么你只需要改变你的html标记,而不用改动你的CSS。

不推荐

div.content > header.content-header > h2.title {
    font-size: 2em;
}

推荐

.content > .content-header > .title {
    font-size: 2em;
}

缩写属性

CSS提供了各种缩写属性(如 font 字体)应该尽可能使用,即使在只设置一个值的情况下。

使用缩写属性对于代码效率和可读性是有很有用的。

不推荐

border-top-style: none;
font-family: palatino, georgia, serif;
font-size: 100%;
line-height: 1.6;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;

推荐

border-top: 0;
font: 100%/1.6 palatino, georgia, serif;
padding: 0 1em 2em;

0 和 单位

省略“0”值后面的单位。不要在0值后面使用单位,除非有值。

不推荐

padding-bottom: 0px;
margin: 0em;

推荐

padding-bottom: 0;
margin: 0;

十六进制表示法

在可能的情况下,使用3个字符的十六进制表示法。 颜色值允许这样表示, 3个字符的十六进制表示法更简短。

始终使用小写的十六进制数字。

不推荐

color: #FF33AA;

推荐

color: #f3a;

ID 和 Class(类) 名的分隔符

使用连字符(中划线)分隔ID和Class(类)名中的单词。为了增强课理解性,在选择器中不要使用除了连字符(中划线)以为的任何字符(包括没有)来连接单词和缩写。

另外,作为该标准,预设属性选择器能识别连字符(中划线)作为单词[attribute|=value]的分隔符, 所以最好的坚持使用连字符作为分隔符。

不推荐

.demoimage {}
.error_status {}

推荐

#video-id {}
.ads-sample {}

声明顺序

这是一个选择器内书写CSS属性顺序的大致轮廓。这是为了保证更好的可读性和可扫描重要。

作为最佳实践,我们应该遵循以下顺序(应该按照下表的顺序):

  1. 结构性属性:
    1. display
    2. position, left, top, right etc.
    3. overflow, float, clear etc.
    4. margin, padding
  2. 表现性属性:
    1. background, border etc.
    2. font, text

不推荐

.box {
    font-family: 'Arial', sans-serif;
    border: 3px solid #ddd;
    left: 30%;
    position: absolute;
    text-transform: uppercase;
    background-color: #eee;
    right: 30%;
    display: block;
    font-size: 1.5rem;
    overflow: hidden;
    padding: 1em;
    margin: 1em;
}

推荐

.box {
    display: block;
    position: absolute;
    left: 30%;
    right: 30%;
    overflow: hidden;
    margin: 1em;
    padding: 1em;
    background-color: #eee;
    border: 3px solid #ddd;
    font-family: 'Arial', sans-serif;
    font-size: 1.5rem;
    text-transform: uppercase;
}

声明结束

为了保证一致性和可扩展性,每个声明应该用分号结束,每个声明换行。

不推荐

.test {
    display: block; height: 100px
}

推荐

.test {
    display: block;
    height: 100px;
}

属性名结束

属性名的冒号后使用一个空格。出于一致性的原因, 属性和值(但属性和冒号之间没有空格)的之间始终使用一个空格。

不推荐

h3 {
    font-weight:bold;
}

推荐

h3 {
    font-weight: bold;
}

选择器和声明分离

每个选择器和属性声明总是使用新的一行。

不推荐

a:focus, a:active {
    position: relative; top: 1px;
}

推荐

h1,
h2,
h3 {
    font-weight: normal;
    line-height: 1.2;
}

规则分隔

规则之间始终有一个空行(双换行符)分隔。

推荐

html {
    background: #fff;
}
 
body {
    margin: auto;
    width: 50%;
}

CSS引号

属性选择器或属性值用双引号(" "),而不是单引号(' ')括起来。 URI值(url())不要使用引号。

不推荐

@import url('//cdn.com/foundation.css');
 
html {
    font-family: 'open sans', arial, sans-serif;
}
 
body::after {
    content: 'pause';
}

推荐

@import url(//cdn.com/foundation.css);
 
html {
    font-family: "open sans", arial, sans-serif;
}
 
body::after {
    content: "pause";
}

伪类选择器和伪类元素

伪类选择器使用一个冒号(:)(i.e. :first-letter, :hover, :active etc) 伪类元素使用一个双冒号(::)(i.e. ::before and ::after

推荐

.button:hover {}

.content::before {}

选择器嵌套 (LESS)

在Less中你可以嵌套选择器,这可以使代码变得更清洁和可读。嵌套所有的选择器,但尽量避免嵌套没有任何内容的选择器。 如果你需要指定一些子元素的样式属性,而父元素将不什么样式属性, 可以使用常规的CSS选择器链。 这将防止您的脚本看起来过于复杂。 (Less 中 &有连接的意思)

不推荐

.content {
    display: block;
}
 
.content > .news-article > .title {
    font-size: 1.2em;
}

推荐

.content {
    display: block;
 
    & > .news-article {
        & > .title {
            font-size: 1.2em;
        }
    }
}

JavaScript 规范 (ECMAScript 5)


全局命名空间污染与 IIFE

总是将代码包裹成一个 IIFE(Immediately-Invoked Function Expression),用以创建独立隔绝的定义域。这一举措可防止全局命名空间被污染。

IIFE 还可确保你的代码不会轻易被其它全局命名空间里的代码所修改(i.e. 第三方库,window 引用,被覆盖的未定义的关键字等等)。

不推荐

var x = 10,
    y = 100;
 
console.log(window.x + ' ' + window.y);

推荐

(function(log, w, undefined){
    'use strict';
 
    var x = 10,
            y = 100;
 
    log((w.x === undefined) + ' ' + (w.y === undefined));
 
}(window.console.log, window));

IIFE(立即执行的函数表达式)

无论何时,想要创建一个新的封闭的定义域,那就用 IIFE。它不仅避免了干扰,也使得内存在执行完后立即释放。

所有脚本文件建议都从 IIFE 开始。

立即执行的函数表达式的执行括号应该写在外包括号内。虽然写在内还是写在外都是有效的,但写在内使得整个表达式看起来更像一个整体,因此推荐这么做。

不推荐

(function(){})();

推荐

(function(){}());

so,用下列写法来格式化你的 IIFE 代码:

(function(){
    'use strict';
 
    // Code goes here
 
}());

如果你想引用全局变量或者是外层 IIFE 的变量,可以通过下列方式传参:

(function($, w, d){
    'use strict';
 
    $(function() {
        w.alert(d.querySelectorAll('div').length);
    });
}(jQuery, window, document));

使用 ECMA Script 5

建议使用 ECMA Script 5 中新增的语法糖和函数。这将简化你的程序,并让你的代码更加灵活和可复用。


严格模式

ECMAScript 5 严格模式可在整个脚本或独个方法内被激活。它对应不同的 javascript 语境会做更加严格的错误检查。严格模式也确保了 javascript 代码更加的健壮,运行的也更加快速。

严格模式会阻止使用在未来很可能被引入的预留关键字。

你应该在你的脚本中启用严格模式,最好是在独立的 IIFE 中应用它。避免在你的脚本第一行使用它而导致你的所有脚本都启动了严格模式,这有可能会引发一些第三方类库的问题。

不推荐

// Script starts here
'use strict';
 
(function(){
 
    // Your code starts here
 
}());

推荐

(function(){
     'use strict';
    // Your code starts here
 
}());

变量声明

总是使用 var 来声明变量。如不指定 var,变量将被隐式地声明为全局变量,这将对变量难以控制。如果没有声明,变量处于什么定义域就变得不清(可以是在 Document 或 Window 中,也可以很容易地进入本地定义域)。所以,请总是使用 var 来声明变量。

采用严格模式带来的好处是,当你手误输入错误的变量名时,它可以通过报错信息来帮助你定位错误出处。

不推荐

x = 10;
y = 100;

推荐

var x = 10,
    y = 100;

定义域提升

把赋值尽量写在变量申明中。

不推荐

var a,
    b,
    c;
 
a = 10;
b = 10;
c = 100;

推荐

var a = 10,
    b = 10,
    c = 100;

eval 函数(魔鬼)

eval() 不但混淆语境还很危险,总会有比这更好、更清晰、更安全的另一种方案来写你的代码,因此尽量不要使用 evil 函数。


合理使用 switch

switch 语句主要是为避免让开发者编写下面的代码:

不推荐

if (i == 20)
    alert("20");
else if (i == 30)
    alert("30");
else if (i == 40)
    alert("40");
else
    alert("other");

推荐

switch (i) {
    case 20: alert("20");
        break;
    case 30: alert("30");
        break;
    case 40: alert("40");
        break;
     default: alert("other");
}

数组和对象字面量

用数组和对象字面量来代替数组和对象构造器。数组构造器很容易让人在它的参数上犯错。

不推荐

var a1 = new Array(x1, x2, x3);

var o2 = new Object();
o2.a = 0;
o2.b = 1;
o2.c = 2;
o2['strange key'] = 3;

推荐

var a = [x1, x2, x3];

var o2 = {
    a: 0,
    b: 1,
    c: 2,
    'strange key': 3
};

字符串

统一使用单引号(‘),不使用双引号(“)。这在创建 HTML 字符串非常有好处:

var msg = 'This is some HTML <div class="makes-sense"></div>';

三元条件判断(if 的快捷方法)

用三元操作符分配或返回语句。在比较简单的情况下使用,避免在复杂的情况下使用。没人愿意用 10 行三元操作符把自己的脑子绕晕。

不推荐

if (x === 10) {
    return 'valid';
} else {
    return 'invalid';
}

推荐

return x === 10 ? 'valid' : 'invalid';

语句块内的函数声明

切勿在语句块内声明函数,在 ECMAScript 5 的严格模式下,这是不合法的。函数声明应该在定义域的顶层。但在语句块内可将函数申明转化为函数表达式赋值给变量。

不推荐

if (x) {
    function foo() {}
}

推荐

if (x) {
    var foo = function() {};
}

分号与函数

JavaScript 中语句要以分号结束,否则它将会继续执行下去,不管换不换行。 分号需要用在表达式的结尾,而并非函数声明的结尾。区分它们最好的例子是:

var foo = function() {
    return true;
}; // semicolon here.

function foo() {
    return true;
} // no semicolon here.