目录
文中带
!!!
表示为强制性规范,其他表示为推荐类规范
❌表示错误写法举例,✅表示正确示范写法
HTML 规范
参考资料
文档基础规范
1.声明文档版本!!!
<!-- ❌ 非 HTML 5 DOCTYPE -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
</html>
<!-- ✅ -->
<!DOCTYPE html>
<html>
</html>
2.声明文档语言
<html lang="zh-CN">
<!-- ... -->
</html>
3.设置元数据
<head>
<!-- 字符编码 -->
<meta charset="UTF-8">
<!-- 关键字 -->
<meta name="keyword" content="关键字">
<!-- 内容描述 -->
<meta name="description" content="描述信息...">
<!--
页面提供给移动设备使用时,需要设置viewport
viewport-fit=cover: 用于兼容iPhoneX的刘海屏
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
</head>
4.设置标题!!!
<head>
<!-- 指定title标签,有且仅有一个 -->
<title>Document</title>
</head>
资源加载规范
1.省略type
link的type默认值为text/css;
srcipt的type默认值为text/jacascript;
<!-- ❌ -->
<link type="text/css" rel="stylesheet" href="demo.css" />
<style type="text/css">
/* ... */
</style>
<script type="text/javascript" src="demo.js"></script>
<!-- ✅ -->
<link rel="stylesheet" href="demo.css" />
<style>
/* ... */
</style>
<script src="demo.js"></script>
2.省略协议部分
外部资源的引用地址跟随页面协议
<!-- ❌ -->
<link rel="stylesheet" href="https://example.com" />
<script src="https://example.com"></script>
<!-- ✅ -->
<link rel="stylesheet" href="//example.com" />
<script src="//example.com"></script>
3.预加载关键资源
<link rel="preload" href="example.css" as="style" />
<link rel="preload" href="example.js" as="script" />
4.DNS解析延迟问题处理
<link rel="preconnect" href="//fonts.example.com/" crossorigin />
<link rel="dns-prefetch" href="//fonts.example.com/" />
5.建议head标签内引入css
css应在head中引入,因为在body中指定外部样式表和嵌入样式表可能会导致页面的重排和重绘
了解更多
<!-- ❌ -->
<body>
<style>
.mod-example {
padding-left: 15px;
}
</style>
</body>
<!-- ✅ -->
<head>
<style>
.mod-example {
padding-left: 15px;
}
</style>
</head>
5.建议body结束标签前引入js
除了基础库等必须要在DOM加载之前运行,其他js脚本都在靠近body结束标签前引入,以防止页面渲染的阻塞。
了解更多
<!-- ❌ -->
<head>
<script src="example.js"></script>
</head>
<!-- ✅ -->
<body>
...
<script src="example.js"></script>
</body>
编码规范
1.缩进
统一使用 2 个空格缩进,不要使用 4 个空格或 tab 缩进
<!-- ❌ -->
<!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>
<!-- ✅ -->
<!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>
2.注释
1.不允许出现敏感信息,如个人隐私、公司内部信息、密码等!!!
2.单行注释,注释内容和注释符之间保留一个空格
3.多行注释,注释符单独占一行,注释内容2个空格缩进
<!-- 单行注释 -->
<!--
多行注释
多行注释
-->
3.标签
- 尽量保持标签语义化
<!-- ❌ -->
<p>标题</p>
<!-- ✅ -->
<h3>标题</h3>
- 标签名使用小写!!!
<!-- ❌ -->
<H1></H1>
<!-- ✅ -->
<h1></h1>
- 单标签不用省略结尾处的斜线,且斜线前要保留一个空格
<!-- ❌ -->
<img src="example.png" alt="example">
<!-- ✅ -->
<img src="example.png" alt="example" />
4.属性
- 属性值使用双引号
""
,不要使用单引号!!!
<!-- ❌ -->
<div class='example'></div>
<!-- ✅ -->
<div class="example"></div>
- Boolean属性不要声明取值
因为Boolean属性存在即表示true,不存在则表示false了解更多
<!-- ❌ -->
<input type="text" disabled="disabled" />
<!-- ✅-->
<input type="text" disabled />
- 自定义属性命名以
data-
为前缀
<!-- ❌ -->
<button list="example"></div>
<!-- ✅ -->
<button data-list="example"></button>
- 可访问性
<!-- ❌ 缺少 alt 属性,无法被无障碍阅读器识别 -->
<img src="hello.jpg" />
<!-- ✅ -->
<img src="hello.jpg" alt="Welcome to visit!" />
<!-- ✅ 图片无需被无障碍阅读器识别时 -->
<img src="logo.jpg" alt="" />
<!-- ✅ 图片无需被无障碍阅读器识别时 -->
<img src="logo.jpg" role="presentation" />
模板
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="description" content="描述信息..." />
<meta name="keyword" content="关键字a,关键字b,关键字c" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, viewport-fit=cover" />
<title>xx网</title>
<link rel="stylesheet" href="example.css" />
<style>
/* 样式 */
</style>
<link rel="stylesheet" href="//example.com" />
<script src="//example.com"></script>
</head>
<body>
<!-- 单行注释 -->
<!--
多行注释...
多行注释...
-->
<h3 id="container">标题</h3>
<div class="content">
<input data-demoData="123456" disabled />
<img src="example.png" alt="example!" />
</div>
...
<script src="example.js"></script>
<script>
// ...
</script>
</body>
</html>
CSS规范
基本规范
- 必须以分号结尾 !!!
- 使用2个空格缩进
- 声明块的右大括号
}
应单独成行 - 单行代码不要超过100个字符
- 选择器和
{}
之间保留一个空格 - 属性声明单独成行(即使只有一条语句)
- 属性名和
:
之间无空格,属性值和:
之间保留一个空格 - 尽量不要使用@import, 否则会导致浏览器处理 CSS 文件速度变慢
/* ❌ */
.header{width:100px;
height:100px
}
/* ✅ */
.main {
width: 100px;
height: 100px;
}
注释规范
- 注释内容和注释符之间留有一个空格
/* ❌ */
.box {
/*comment*/
/* comment */
/**
*comment
*/
padding: 10px;
}
/* ✅ */
.box {
/* comment */
/**
* comment
*/
padding: 10px;
}
- 注释行上方需留有一行空行,除非上一行是注释或块的顶部
/* ❌ */
.box {
/* comment */
width: 100px;
/* comment */
height: 100px;
}
/* ✅ */
.box {
/* comment */
width: 100px;
/* comment */
height: 100px;
}
选择器规范
>
、+
、~
、||
等组合选择器符号前后保留一个空格
/* ❌ */
.header > .leftText {
padding: 10px;
}
/* ✅ */
.header > .leftText {
padding: 10px;
}
- 使用多个选择器时,每个选择器应该单独成行;
/* ❌ */
.header, .main, .footer {
padding: 10px;
}
/* ✅ */
.header,
.main,
.footer {
padding: 10px;
}
- 组合选择器内的条目尽量不超过3个
/* ❌ */
.header > .content > .box > .left > .logo {
padding: 10px;
}
/* ✅ */
.header > .left > .logo {
padding: 10px;
}
- 尽量不使用
id
选择器, 尽量使用class
选择器而不是标签
选择器 - 属性选择器的值始终用双引号包裹
/* ❌ */
input[type=text] {
width: 100px;
}
/* ✅ */
input[type="text"] {
width: 100px;
}
- 选择器效率排行(只从效率看)
- ID 选择器, 比如
#header
- 类选择器,比如
.header
- 标签(元素)选择器,比如
div
- 相邻兄弟选择器,比如
h2 + p
- 子选择器,比如
ul > li
- 后代选择器,比如
ul a
- 通配符选择器,比如
*
- 属性选择器,比如
[class^="grid-"]
- 伪类(伪元素)选择器,比如
a:hover
、a::before
属性规范
- 尽可能不要用!important
- 根据情况使用简写属性
/* ❌ */
.box {
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
}
/* ✅ */
.box {
padding: 10px;
}
,
分隔的属性值之后保留一个空格
/* ❌ */
.box {
padding: 10px 20px;
}
/* ✅ */
.box {
padding: 10px 20px;
}
- 使用尽可能短的十六进制值, 且使用小写字母
/* ❌ */
.box {
color: #FFFFFF;
}
/* ✅ */
.box {
color: #fff;
}
- 长度值为0时,省略掉长度单位
/* ❌ */
.box {
padding: 0px;
}
/* ✅ */
.box {
padding: 0;
}
- 保留小数点前的0,保持可读性(存在争议)
/* ❌ */
.box {
opacity: .5;
}
/* ✅ */
.box {
opacity: 0.5;
}
- 注意属性声明的顺序
- 定位:如 position、left、right、top、bottom、z-index
- 盒模型:如 display、float、width、height、margin、padding、border
- 文字排版:如 font、color、line-height、text-align
- 外观:如 background
- 其他属性
JavaScript
编码风格
缩进!!!
使用2个空格缩进
分号!!!
必须使用分号结尾
逗号!!!
逗号分隔的多行结构,必须加上最后一个逗号,且不能使用行首逗号!!!
// ❌
const a = {
a: 1
, b: 2
, c: 3
}
// ✅
const a = {
a: 1,
b: 2,
c: 3,
}
块 {}
!!!
包含类、函数、控制等由
{}
分隔的代码块结构
// ❌
if (a == b)
return 1;
else
return 2;
// ✅
if (a == b) {
return 1;
} else if (a == c) {
return 2;
} else {
// TODO, 此处写明注释,不能出现空代码块
}
空格!!!
- 函数、控制语句等等左大括号前有一个空格
// ❌
function add(){
// ...
}
// ✅
function add() {
// ...
}
- 函数名和
()
之间无空格,
// ❌
function add (){
// ...
}
// ✅
function add() {
// ...
}
()
、[]
内两侧无空格,{}
内两侧有空格
// ❌
function add( 1,2 ) {
// ...
}
const arr = [ 1, 2 ];
const obj = {a: 1, b: 2};
// ✅
function add(1, 2) {
// ...
}
const arr = [1, 2];
const obj = { a: 1, b: 2 };
- 运算符(非一元)两侧有空格
// ❌
const x = 1 + y;
const a = ! x;
// ✅
const x = 1 + y;
const a = !x;
- 键名和键值之间有一个空格
// ❌
const obj = {
a:1,
b:true,
};
// ✅
const obj = {
a: 1,
b: true,
};
行
文件末尾保留一行空行;
文件最大行数1000;
单行最大字符数100;
语言特性
变量声明
- 尽量使用且正确使用const、let,不要使用var或者直接声明, 否则容易污染全局命名空间;
- 一条声明语句声明一个变量;
// ❌
const a = 1,
b = 2;
// ✅
const a = 1;
const b = 2;
- 禁止连续赋值
// ❌
(function() {
let a = b = c = 1; // b、c会变成全局变量
})();
// ✅
(function() {
let c = 1;
let b = c;
let a = b;
})();
原始类型
- 不要使用
new Number/String/Boolean
, 会导致变量成为’object’类型
// ❌
const bool = new Boolean(false);
if (bool) {
// bool是对象,所以永远是true
}
// ✅
const bool = false;
- 建议使用
Number()
、parseInt()、 String()、!!
进行类型转换; - 使用
parseInt()
时总是带上基数(进制)
const str = '1';
const num = 0;
// ❌
// 转数字
const num1 = +str;
const num2 = str >> 0;
// 转布尔值
const bool1 = newBoolean(num);
// 转字符串
const str1 = new String(num);
const str2 = num + '';
const str3 = num.toString();
// ✅
// 转数字
const num11 = Number(str);
const num12 = parseInt(str, 10);
// 转布尔值
const bool11 = !!num;
// 转字符串
const str11 = String(num);
- 字符优先使用单引号
''
,需要拼接时可使用模板字符串、禁止不必要的转译字符
// ❌
const str = "hello";
const str2 = '\'this\' \i\s \"hello\"';
// ✅
const str11 = 'hello';
const str12 = `'this' is 'hello'"`;
数组
- 使用字面量创建数组
// ❌
const arr1 = new Array(1, 2, 3);
const arr2 = Array(1, 2, 3);
// ✅
const arr = [1, 2, 3];
const arr12 = new Array(10); // 除非设置长度
- 某些数组方法的回调函数中必须包含return语句,如some、map、find等需要,forEach则不需要
- 使用扩展运算符
...
处理数组,代替concat、map等。
const arr = [1, 2, 3, 4, 5];
// ❌
const arr1 = arr.map(item => item);
// ✅
const arr2 = [...arr];
- 使用对象解构数组
// ❌
function getPosition(div) {
return [left, right, top, bottom];
}
const [left, _, top] = getPosition(div);
// ✅
function getPosition(div) {
return { left, right, top, bottom };
}
const { left, top } = getPosition(div);
对象
- 使用字面量创建对象
// ❌
const obj1 = new Object();
// ✅
const obj2 = {};
- 使用对象属性和方法等简写语法,且简写的属性写一起
// ❌
const num = 1;
const str = 'hello world';
const obj1 = {
num: num,
add: function() {
return num + 1;
},
str: str,
}
// ✅
const obj2 = {
num,
str,
add() {
return num + 1;
}
};
- 属性名不要用引号, 除非包含特殊字符
// ❌
const obj1 = {
'num': 1,
'str': 'hello world',
'data-1': 12,
}
// ✅
const obj2 = {
num: 1,
str: 'hello world',
'data-1': 12,
}
- 优先使用
.
访问对象的属性
const obj = {
a: 1,
}
// ❌
const a1 = obj['a'];
// ✅
const a2 = obj.a;
- 使用扩展运算符
...
处理对象
const obj = {
a: 1,
b: 2,
}
// ❌
const obj1 = Object.assign(obj, {c: 3});
const obj2 = Object.assign({}, original, {c: 3});
// ✅
const obj2 = {...obj, c: 3};
- 使用解构获取
...
对象属性
const obj = {
a: 1,
b: 2,
}
// ❌
const a = obj.a;
const b = obj.b;
// ✅
const {a, b} = obj;
函数
- 不要使用
new Function
构造函数创建函数;
// ❌
const add = new Function('a', 'b' 'return a + b');
// ✅
const add = (a, b) => (a + b);
- 不要在块中使用函数声明
函数声明会有函数提升,在块外也能使用,容易产生不必要的风险。
// ❌
if (true) {
function add1() {
console.log('adding1');
}
}
add(); // 能执行
// ✅
if (true) {
const add2 = function () {
console.log('adding2');
};
}
add2(); // add2 is not defined
- 使用箭头函数代替匿名函数
代码简洁,且可以解决this指向的问题
- 不要使用
arguments
, 可以使用...args
替代
// ❌
function add1(a, b) {
const args = Array.prototype.slice.call(arguments, add.length);
console.log(args);
}
add1(1, 2, 3, 4); // [3, 4];
// ✅
function add2(a, b, ...args) {
console.log(args);
}
add2(1, 2, 3, 4); // [3, 4];
类
- 使用
class
替代prototype
// ❌
function Person() {
this.age = 20;
}
Person.prototype.add = function() {
this.age += 1;
}
// ✅
class Person {
constructor() {
this.age = 20;
}
add() {
this.age += 1;
}
}
- 使用
extends
进行类的继承
// ✅
class ChinesePerson extends Person {
// ...
}
模块
- 使用ES6 modules, 除非Node.js运行环境
// ❌
const Demo = require('demo');
module.exports = Demo;
// ✅
import Demo from 'demo';
export default Demo;
- 不要使用多个import引入同一个模块
// ❌
import {a} from 'demo';
import Demo from 'demo';
import {b} from 'demo';
// ✅
import Demo, {a, b} from 'demo';
- import放到模块最上方
// ❌
import foo from 'foo';
foo.init();
import bar from 'bar';
bar.init();
// ✅
import foo from 'foo';
import bar from 'bar';
foo.init();
bar.init();
- 导入排序规则
- 先第三方模块、 再工程内模块
- 先绝对路径, 再相对路径
- 再模块导入之后保留一个空行
// ❌
import add from 'add';
add();
// ✅
import del from 'del';
del();
操作符
- 使用严格相等运算符
const a = '1';
const b = 2;
// ❌
if (a == b) {
// ...
}
// ✅
if (Number(a) === b) {
// ...
}
- 除了在
for
循环条件中,其他情况不要使用一元自增自减运算符
const a = 1;
// ❌
a ++;
// ✅
a += 1;
- 避免嵌套的三元运算符
// ❌
const z = s === 'a' ? 1: s === 'b'? 2 : 3;
// ✅
const x = s === 'b' ? 2 : 3;
const y = s === 'a' ? 1 : x;
- 混合使用操作符时,使用小括号
()
包裹
// ❌ 容易误以为执行顺序是(a || b) && c
if (a || b ** c) {
//...
}
// ✅
if (a || (b && c)) {
// ...
}
控制语句
- switch 至少要包含3个条件分支,且必须有default分支
- 嵌套层级不要超过四层,如if、for等
- for-in循环中要对key进行验证
// ❌
for (const key in obj) {
console.log(key, obj[key]);
}
// ✅
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
console.log(key, obj[key]);
}
}
注释
- 注释内容和注释符之间保留一个空格
- 单行注释使用
//
, 单独占一行,写在被注释对象上方
// ❌
const a = 1; // this is a
const b = 2; // this is b
// ✅
// this is a
const a = 1;
// this is b
const b = 2;
- 多行注释使用
/** ... */
// ❌
// this is What about the following
// this is element
function add2() {
// ...
}
// ✅
/**
* @description xxx
* @param xxx
*/
function add2() {
// ...
}
- 函数注释使用jsdoc规范
文档类注释,如函数、类、文件、事件等, 推荐使用jsdoc规范 详情
/**
* 加法
* @param {number} a 数字a
* @param {number} b 数字b
*/
function add(a, b) {
return a + b;
}
- 推荐使用文件表头注释
推荐vscode插件 vscode-fileheader
可以显示作者、创建日期、描述等(可以配置自定义显示内容)
/*
* @Author: Tom
* @Date: 2023-08-24 11:53:29
* @Last Modified by: Tom
* @Last Modified time: 2023-08-24 11:53:29
* @Description: 封装的函数
*/
- 合理使用特殊注释标记
// TODO 表示待做的功能
// FIXME 表示待处理的问题
// ...
其他
- 禁止使用eval、debugger、alert、console等(生产环境);
- 禁止对原生对象或只读的全局对象进行赋值,如window = {}; undefined = 1等