前端规范
前端规范文档。
1. HTML
1.1 语法
- 用两个空格来代替制表符(tab) -- 这是唯一能保证在所有环境下获得一致展现的方法。
- 嵌套元素应当缩进一次(即两个空格)。
- 对于属性的定义,确保全部使用双引号,绝不要使用单引号。
- 不要在自闭合(self-closing)元素的尾部添加斜线 -- HTML5 规范中明确说明这是可选的。
- 不要省略可选的结束标签(closing tag)(例如,
</li>
或</body>
)。
<!DOCTYPE html>
<html>
<head>
<title>Page title</title>
</head>
<body>
<img src="images/company-logo.png" alt="Company">
<h1 class="hello-world">Hello, world!</h1>
</body>
</html>
1.2 属性顺序
HTML 属性应当按照以下给出的顺序依次排列,确保代码的易读性。
class
id, name
data-*
src, for, type, href, value
title, alt
role, aria-*
class 属性用于标识高度可复用组件,因此应该排在首位。
id 属性用于标识具体组件,应当谨慎使用(例如,页面内的书签),因此排在第二位。
1.3 布尔(boolean)型属性
布尔型属性可以在声明时不赋值。XHTML 规范要求为其赋值,但是 HTML5 规范不需要。
<input type="text" disabled>
<input type="checkbox" value="1" checked>
<select>
<option value="1" selected>1</option>
</select>
1.4 减少标签的数量
编写 HTML 代码时,尽量避免多余的父元素。很多时候,这需要迭代和重构来实现。请看下面的案例:
<!-- Not so great -->
<span class="avatar">
<img src="...">
</span>
<!-- Better -->
<img class="avatar" src="...">
2. CSS
2.1 编码设置
采用 UTF-8 编码,在 CSS 代码头部使用:@charset "utf-8";
注意,必须要定义在 CSS 文件所有字符的前面(包括编码注释),@charset 才会生效。
例如,下面的例子都会使得 @charset 失效:
/* 字符编码 */
@charset "utf-8";
html,body {
height: 100%;
}
@charset"utf-8";
2.2 命名空间规范
只能出现小写字符和破折号(dashe)(不是下划线,也不是驼峰命名法)
布局:以 g 为命名空间,例如:.g-wrap 、.g-header、.g-content。
状态:以 s 为命名空间,表示动态的、具有交互性质的状态,例如:.s-current、.s-selected。
工具:以 u 为命名空间,表示不耦合业务逻辑的、可复用的的工具,例如:.u-clearfix、.u-ellipsis。
组件:以 m 为命名空间,表示可复用、移植的组件模块,例如:.m-slider、.m-drop-menu。
钩子:以 j 为命名空间,表示特定给 JavaScript 调用的类名,例如:.j-request、.j-open。
建议:
不建议使用下划线 _ 进行连接
节省操作,输入的时候少按一个 shift 键
能良好区分 JavaScript 变量命名
字符小写
定义的选择器名,属性及属性值的书写皆为小写。
2.3 选择器
当一个规则包含多个选择器时,每个选择器独占一行。+、~、>
选择器的两边各保留一个空格。
2.4 规则声明块
当规则声明块中有多个样式声明时,每条样式独占一行。
在规则声明块的左大括号 { 前加一个空格。
在样式属性的冒号 : 后面加上一个空格,前面不加空格。
在每条样式后面都以分号 ; 结尾。
规则声明块的右大括号 } 独占一行。
每个规则声明间用空行分隔。
所有最外层引号使用单引号 ‘ 。
当一个属性有多个属性值时,以逗号 , 分隔属性值,每个逗号后添加一个空格,当单个属性值过长时,每个属性值独占一行。
完整示例如下:
1.5数值与单位
- 当属性值或颜色参数为 0 – 1 之间的数时,省略小数点前的 0 。
// bad
color: rgba(255, 255, 255, 0.5)
// good
color: rgba(255, 255, 255, .5);
- 当长度值为 0 时省略单位。
// bad
margin: 0px auto;
// good
margin: 0 auto;
- 十六进制的颜色属性值使用小写和尽量简写。
// bad
color: #ffcc00;
// good
color: #fc0;
2.6 样式属性顺序
单个样式规则下的属性在书写时,应按功能进行分组,并以 Positioning Model > Box Model > Typographic > Visual 的顺序书写,提高代码的可读性。
如果包含 content 属性,应放在最前面;
Positioning Model 布局方式、位置,相关属性包括:position / top / right / bottom / left / z-index / display / float / …
Box Model 盒模型,相关属性包括:width / height / padding / margin / border / overflow / …
Typographic 文本排版,相关属性包括:font / line-height / text-align / word-wrap / …
Visual 视觉外观,相关属性包括:color / background / list-style / transform / animation / transition / …
Positioning 处在第一位,因为他可以使一个元素脱离正常文本流,并且覆盖盒模型相关的样式。盒模型紧跟其后,因为他决定了一个组件的大小和位置。其他属性只在组件内部起作用或者不会对前面两种情况的结果产生影响,所以他们排在后面。
.declaration-order {
/* Positioning */
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
display: block;
float: right;
/* Box-model */
width: 100px;
height: 100px;
/* Typography */
font: normal 13px "Helvetica Neue", sans-serif;
line-height: 1.5;
color: #333;
text-align: center;
/* Visual */
background-color: #f5f5f5;
border: 1px solid #e5e5e5;
border-radius: 3px;
/* Misc */
opacity: 1;
}
2.7合理使用使用引号
在某些样式中,会出现一些含有空格的关键字或者中文关键字。
- font-family 内使用引号 当字体名字中间有空格,中文名字体及 Unicode 字符编码表示的中文字体,为了保证兼容性,都建议在字体两端添加单引号或者双引号:
body {
font-family: 'Microsoft YaHei', '黑体-简', '\5b8b\4f53';
}
- background-image 的 url 内使用引号 如果路径里面有空格,旧版 IE 是无法识别的,会导致路径失效,建议不管是否存在空格,都添加上单引号或者双引号:
div {
background-image: url('...');
}
2.8避免使用 !important
- 除去某些极特殊的情况,尽量不要不要使用 !important。
- !important 的存在会给后期维护以及多人协作带来噩梦般的影响。
- 当存在样式覆盖层叠时,如果你发现新定义的一个样式无法覆盖一个旧的样式,只有加上 !important 才能生效时,是因为你新定义的选择器的优先级不够旧样式选择器的优先级高。所以,合理的书写新样式选择器,是完全可以规避一些看似需要使用 !important 的情况的。
2.9代码注释
1. 单行注释
星号与内容之间必须保留一个空格。
/* 这是一条单行注释 */
2. 多行注释
星号要一列对齐,星号与内容之间必须保留一个空格。
3. 规则声明块内注释
使用 // 注释,// 后面加上一个空格,注释独立一行。
.g-footer {
border: 0;
// ....
}
4. 文件注释
文件顶部必须包含文件注释,用 @name 标识文件说明。星号要一列对齐,星号与内容之间必须保留一个空格,标识符冒号与内容之间必须保留一个空格。
- @description为文件或模块描述。
- @update为可选项,建议每次改动都更新一下。
当该业务项目主要由固定的一个或多个人负责时,需要添加@author标识,一方面是尊重劳动成果,另一方面方便在需要时快速定位责任人。
5. LESS和SASS 使用建议
- 嵌套层级规定
使用 SASS 、 LESS 等预处理器时,建议嵌套层级不超过 3 层。
组件/公用类的使用方法
组件/公用类使用 %placeholders 定义,使用 @extend 引用。如:
%clearfix {
overflow: auto;
zoom: 1;
}
.g-header {
@extend %clearfix;
}
- 避免不必要的嵌套
只有在必须将样式限制在父元素内(也就是后代选择器),并且存在多个需要嵌套的元素时才使用嵌套。
// Without nesting
.table > thead > tr > th { … }
.table > thead > tr > td { … }
// With nesting
.table > thead > tr {
> th { … }
> td { … }
}
- 尽量避免使用标签名
使用 LESS ,或者说在 CSS 里也有这种困惑。
假设我们有如下 html 结构:
<span>
<div class="g-content">
<ul class="g-content-list">
<li class="item"/>
<li class="item"/>
<li class="item"/>
<li class="item"/>
</ul>
</div>
</span>
在给最里层的标签命名书写样式的时候,我们有两种选择:
// Bad example
.g-content {
.g-content-list {
li {
...
}
}
}
// Good example
.g-content {
.g-content-list {
.item {
...
}
}
}
- .g-content .g-content-list li { }
- .g-content .g-content-list .item { }
基于 CSS 选择器的解析规则(从右向左),建议使用上述第二种.g-content .g-content-list .item { }
,避免使用通用标签名作为选择器的一环可以提高 CSS 匹配性能。
3. JS
3.1 使用空格代替tab
除了每一行的终止符序列,ASCII水平空格符(0x20)是唯一一个可以出现在源文件中任意位置的空格字符。
这也意味着,tab字符不应该被使用,以及被用来控制缩进。
规范随后指出应该使用2个,而不是4个空格带实现缩进。
// bad
function foo() {
let name;
}
// bad
function bar() {
let name;
}
// good 使用2个空格字符缩进
function baz() {
let name;
}
3.2 不能省略分号
每个语句必须以分号结尾。不允许依赖于JS自动添加分号的功能。
尽管我不明白为什么会有人反对这个规则,但目前分号的使用问题显然已经像“空格 vs tab” 这个问题一样产生了巨大的争议。而Google对此表示分号是必须的,是不可省略的。
// bad
let luke = {}
let leia = {}
[luke, leia].forEach(jedi => jedi.father = 'vader')
// good
let luke = {};let leia = {};
[luke, leia].forEach((jedi) => {
jedi.father = 'vader';
});
3.3 不推荐代码水平对齐
Google的代码规范允许但不推荐对代码进行水平对齐。即使之前的代码中做了水平对齐的处理,以后也应该避免这种行为。
对代码进行水平对齐会在代码中添加若干多余的空格,这让相邻两行的字符看上去处于一条垂直线上。
// bad
{
tiny: 42,
longer: 435,
};
// good
{
tiny: 42,
longer: 435,
};
3.4 杜绝var
使用const或let来声明所有局部变量。如果变量不需要被重新赋值,默认应该使用const。应该拒绝使用关键字var。
// bad
var example = 42;
// good
const example = 42;
3.5 优先使用箭头函数
箭头函数提供了一种简洁的语法,并且避免了一些关于this指向的问题。
相比较与function关键字,开发者应该优先使用箭头函数来声明函数,尤其是声明嵌套函数。
坦白说,我曾以为箭头函数的作用只在于简洁美观。但现在我发现原来它们还有更重要的作用。
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
3.6 使用模板字符串取代连接字符串
在处理多行字符串时,模板字符串比复杂的拼接字符串要表现的更出色。
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
3.7 不要使用续行符分割长字符串
在JS中,\也代表着续行符。Google的代码规范不允许在不管是模板字符串还是普通字符串中使用续行符。
尽管ES5中允许这么做,但如果在\后跟着某些结束空白符,这种行为会导致一些错误,而这些错误在审阅代码时很难注意到。
// bad (建议在PC端阅读)
const longString = 'This is a very long string that \
far exceeds the 80 column limit. It unfortunately \
contains long stretches of spaces due to how the \
continued lines are indented.';
// good
const longString = 'This is a very long string that ' +
'far exceeds the 80 column limit. It does not contain ' +
'long stretches of spaces since the concatenated ' +
'strings are cleaner.';
3.8 优先使用for...of
在ES6中,有3种不同的for循环。尽管每一种有它的应用场景,但Google仍推荐使用for...of。
真有趣,Google居然会特别指定一种for循环。虽然这很奇怪,但不影响我接受这一观点。
以前我认为for...in适合遍历Object,而for...of适合遍历数组。因为我喜欢这种各司其职的使用方式。
尽管Google的规范与这种使用方式相冲突,但Google对for...of的偏爱依然让我觉得十分有趣。
3.9 不要使用eval语句
除非是在code loader中,否则不用使用eval或是Function(...string)结构。这个功能具有潜在的危险性,并且在CSP环境中无法起作用。
// bad
let obj = { a: 20, b: 30 };
let propName = getPropName(); // returns "a" or "b"
eval( 'var result = obj.' + propName );
// good
let obj = { a: 20, b: 30 };
let propName = getPropName(); // returns "a" or "b"
let result = obj[ propName ]; // obj[ "a" ] is the same as obj.a
3.10 常量的命名规范
常量命名应该使用全大写格式,并用下划线分割
如果你确定一定以及肯定一个变量值以后不会被修改,你可以将它的名称使用全大写模式改写,暗示这是一个常量,请不要修改它的值。
遵守这条规则时需要注意的一点是,如果这个常量是一个函数,那么应该使用驼峰式命名法。
// bad
const number = 5;
// good
const NUMBER = 5;
3.11 每次只声明一个变量
每一个变量声明都应该只对应着一个变量。不应该出现像let a = 1,b = 2;这样的语句。
// bad
let a = 1, b = 2, c = 3;
// good
let a = 1;
let b = 2;
let c = 3;
3.12 使用单引号
只允许使用单引号包裹普通字符串,禁止使用双引号。如果字符串中包含单引号字符,应该使用模板字符串。
// bad
let directive = "No identification of self or mission."
// bad
let saying = 'Say it ain\u0027t so.';
// good
let directive = 'No identification of self or mission.';
// good
let saying = `Say it ain't so`;