# 命名规范

# 目录命名

  • 项目文件夹:projectname
  • 样式文件夹:css
  • 脚本文件夹:js
  • 样式类图片文件夹:img

# 图片命名

# 命名顺序

  • 图片命名建议以以下顺序命名:
图片业务(可选) +(mod_)图片功能类别(必选)+ 图片模块名称(可选) + 图片精度(可选)
  • 图片业务:
pp_:拍拍
wx_:微信
sq_:手Q
jd_:京东商城
  • 图片功能类别:
mod_:是否公共,可选
icon:模块类固化的图标
logo:LOGO类
spr:单页面各种元素合并集合
btn:按钮
bg:可平铺或者大背景
  • 图片模块名称:
goodslist:商品列表
goodsinfo:商品信息
userava tar:用户头像
  • 图片精度:
普清:@1x
Retina:@2x | @3x
  • 示例:
公共模块:
wx_mod_btn_goodlist@2x.png
wx_mod_btn_goodlist.png
mod_btn_goodlist.png 
非公共模块:
wx_btn_goodlist@2x.png
wx_btn_goodlist.png
btn_goodlist.png
  • 交叉业务协作 业务交叉协作的时候,为了避免图片命名冲突,建议图片名加上业务和模块前辍,如拍拍侧和手Q侧的业务交叉合作时,侧栏导航icon雪碧图命名:
推荐:
pp_icon_mod_sidenav.png
不推荐:
icon_mod_sidenav.png
  • 处理高清图片的时候,命名应该加上图片相应的精度说明
推荐:
jdc_logo@1x.png
jdc_logo@2x.png
不推荐:
jdc_logo.png
jdc_logo_retina.png

# HTML/CSS文件命名

确保文件命名总是以字母开头而不是数字,且字母一律小写,以下划线连接且不带其他标点符号,如:

<!-- HTML -->
jdc.html
jdc_list.html
jdc_detail.html
<!-- SASS -->
jdc.scss
jdc_list.scss
jdc_detail.scss

# ClassName命名

ClassName的命名应该尽量精短、明确,必须以字母开头命名,且全部字母为小写,单词之间统一使用下划线 “_” 连接。

  • 命名原则

基于姓氏命名法(继承 + 外来)祖先模块不能出现下划线,除了是全站公用模块,如 mod_ 系列的命名。

推荐:

<div class="modulename">
	<div class="modulename_info">
		<div class="modulename_son"></div>
		<div class="modulename_son"></div>
	</div>
</div>
<!-- 这个是全站公用模块,祖先模块允许直接出现下划线 -->
<div class="mod_info">
	<div class="mod_info_son"></div>
	<div class="mod_info_son"></div>
</div>

不推荐:

<div class="modulename_info">
	<div class="modulename_info_son"></div>
	<div class="modulename_info_son"></div>
	...		
</div>

在子孙模块数量可预测的情况下,严格继承祖先模块的命名前缀

<div class="modulename">
	<div class="modulename_cover"></div>
	<div class="modulename_info"></div>
</div>

当子孙模块超过4级或以上的时候,可以考虑在祖先模块内具有识辨性的独立缩写作为新的子孙模块 推荐:

<div class="modulename">
	<div class="modulename_cover"></div>
	<div class="modulename_info">
    	<div class="modulename_info_user">
    		<div class="modulename_info_user_img">
    			<img src="" alt="">
    			<!-- 这个时候 miui 为 modulename_info_user_img 首字母缩写-->
    			<div class="miui_tit"></div>
    			<div class="miui_txt"></div>
    			...
    		</div>
    	</div>
    	<div class="modulename_info_list"></div>
	</div>
</div>

不推荐:

<div class="modulename">
	<div class="modulename_cover"></div>
	<div class="modulename_info">
    	<div class="modulename_info_user">
    		<div class="modulename_info_user_img">
    			<img src="" alt="">
    			<div class="modulename_info_user_img_tit"></div>
    			<div class="modulename_info_user_img_txt"></div>
    			...
    		</div>
    	</div>
    	<div class="modulename_info_list"></div>
	</div>
</div>
  • 模块命名

全站公共模块:以 mod_ 开头

<div class="mod_yours"></div>

业务公共模块:以 业务名_mod_ 开头

<div class="paipai_mod_yours"></div>
  • 常用命名推荐

注意:ad、banner、gg、guanggao 等有机会和广告挂勾的字眠不建议直接用来做ClassName,因为有些浏览器插件(Chrome的广告拦截插件等)会直接过滤这些类名。

<div class="ad"></div>

这种广告的英文或拼音类名不应该出现。另外,敏感不和谐字眼也不应该出现,如:

<div class="fuck"></div>
<div class="jer"></div>
<div class="sm"></div>
<div class="gcd"></div> 
<div class="ass"></div> 
<div class="KMT"></div> 

# HTML规范

# 代码规范

# DOCTYPE 声明

一个DOCTYPE必须包含以下部分,并严格按照顺序出现:

一个ASCII字符串 “<!DOCTYPE” ,大小写不敏感
一个或多个空白字符
一个ASCII字符串”html”,大小写不敏感
一个可选的历史遗留的DOCTYPE字符串 (DOCTYPE legacy string),或者一个可选的已过时但被允许的DOCTYPE字符串 (obsolete permitted DOCTYPE string) 字符串
一个或多个空白字符
一个编码为 U+003E 的字符 “>”

# 团队约定

HTML文件必须加上 DOCTYPE 声明,并统一使用 HTML5 的文档声明:

<!DOCTYPE html>

# 页面语言LANG

Lang属性的取值应该遵循互联网工程任务组–IETF(The Internet Engineering Task Force)制定的关于语言标签的文档 BCP 47 - Tags for Identifying Languages

# 团队约定

推荐使用属性值 cmn-Hans-CN(简体, 中国大陆),但是考虑浏览器和操作系统的兼容性,目前仍然使用 zh-CN 属性值

<html lang="zh-CN">

# 更多地区语言参考

zh-SG 中文 (简体, 新加坡)   对应 cmn-Hans-SG 普通话 (简体, 新加坡)
zh-HK 中文 (繁体, 香港)     对应 cmn-Hant-HK 普通话 (繁体, 香港)
zh-MO 中文 (繁体, 澳门)     对应 cmn-Hant-MO 普通话 (繁体, 澳门)
zh-TW 中文 (繁体, 台湾)     对应 cmn-Hant-TW 普通话 (繁体, 台湾)

# CHARSET

因为 ISO-8859 中字符集大小是有限的,且在多语言环境中不兼容,所以 Unicode 联盟开发了 Unicode 标准。
Unicode 标准覆盖了(几乎)所有的字符、标点符号和符号。
Unicode 使文本的处理、存储和运输,独立于平台和语言。
HTML-5 中默认的字符编码是 UTF-8

# 团队约定

一般情况下统一使用 “UTF-8” 编码

<meta charset="UTF-8">

由于历史原因,有些业务可能会使用 “GBK” 编码

<meta charset="GBK">

请尽量统一写成标准的“UTF-8”,不要写成 “utf-8” 或 “utf8” 或 “UTF8”。

根据 IETF对UTF-8的定义,其编码标准的写法是 “UTF-8”;而 UTF8 或 utf8的写法只是出现在某些编程系统中,如 .NET framework的类System.Text.Encoding中的一个属性名就叫 UTF8。

# 元素及标签闭合

HTML元素共有以下5种:

  • 空元素:area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr

  • 原始文本元素:script、style RCDATA元素:textarea、title

  • 外来元素:来自MathML命名空间和SVG命名空间的元素。

  • 常规元素:其他HTML允许的元素都称为常规元素。 元素标签的闭合应遵循以下原则:

  • 原始文本元素、RCDATA元素以及常规元素都有一个开始标签来表示开始,一个结束标签来表示结束。

  • 某些元素的开始和结束标签是可以省略的,如果规定标签不能被省略,那么就绝对不能省略它。

  • 空元素只有一个开始标签,且不能为空元素设置结束标签。

  • 外来元素可以有一个开始标签和配对的结束标签,或者只有一个自闭合的开始标签,且后者情况下该元素不能有结束标签。

# 团队约定

为了能让浏览器更好的解析代码以及能让代码具有更好的可读性,有如下约定:

所有具有开始标签和结束标签的元素都要写上起止标签,某些允许省略开始标签或和束标签的元素亦都要写上。 空元素标签都不加 “/” 字符

推荐:

<div>
    <h1>我是h1标题</h1>
    <p>我是一段文字,我有始有终,浏览器能正确解析</p>
</div>
<br>

不推荐:

<div>
    <h1>我是h1标题</h1>
    <p>我是一段文字,我有始无终,浏览器亦能正确解析
</div>
<br/>

# 书写风格

# HTML代码大小写

  • HTML标签名、类名、标签属性和大部分属性值统一用小写

推荐:

<div class="demo"></div>

不推荐:

<div class="DEMO"></div>	
<DIV CLASS="DEMO"></DIV>
  • HTML文本、CDATA、JavaScript、meta标签某些属性等内容可大小写混合
<!-- 优先使用 IE 最新版本和 Chrome Frame -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>

<!-- HTML文本内容 -->
<h1>I AM WHAT I AM </h1>

<!-- JavaScript 内容 -->
<script type="text/javascript">
	var demoName = 'demoName';
	...
</script>
	
<!-- CDATA 内容 -->
<script type="text/javascript"><![CDATA[
...
]]></script>

# 类型属性

  • 不需要为 CSS、JS指定类型属性,HTML5 中默认已包含

推荐:

<link rel="stylesheet" href="" >
<script src=""></script>

不推荐:

<link rel="stylesheet" type="text/css" href="" >
<script type="text/javascript" src="" ></script>

# 元素属性

  • 元素属性值使用双引号语法
  • 元素属性值可以写上的都写上

推荐:

<input type="text">
	
<input type="radio" name="name" checked="checked" >

不推荐:

<input type=text>	
<input type='text'>
	
<input type="radio" name="name" checked >

# 特殊字符引用

文本可以和字符引用混合出现。这种方法可以用来转义在文本中不能合法出现的字符。

在 HTML 中不能使用小于号 “<” 和大于号 “>”特殊字符,浏览器会将它们作为标签解析,若要正确显示,在 HTML 源代码中使用字符实体

推荐:

<a href="#">more&gt;&gt;</a>

不推荐:

<a href="#">more>></a>

# 代码缩进

统一使用四个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)

<div class="jdc">
    <a href="#"></a>
</div>

# 纯数字输入框

使用 type="tel" 而不是 type="number"

<input type="tel">

# 代码嵌套

元素嵌套规范,每个块状元素独立一行,内联元素可选

推荐:

<div>
    <h1></h1>
    <p></p>
</div>	
<p><span></span><span></span></p>

不推荐:

<div>
    <h1></h1><p></p>
</div>	
<p> 
    <span></span>
    <span></span>
</p>

段落元素与标题元素只能嵌套内联元素

推荐:

<h1><span></span></h1>
<p><span></span><span></span></p>

不推荐:

<h1><div></div></h1>
<p><div></div><div></div></p>

# 注释规范

遵循标准

  • 必须以4个有序字符开始:编码为 U+003C LESS-THAN SIGN 的小于号, 编码为 U+0021 EXCLAMATION MARK 的感叹号, 编码为 U+002D HYPHEN-MINUS 横线, 编码为 U+002D HYPHEN-MINUS横线 ,即 “<!–”
  • 在此之后是注释内容,注释的内容有以下限制:
* 不能以单个 “>” (U+003E) 字符开始
* 不能以由 “-“(U+002D HYPHEN-MINUS)和 ”>” (U+003E) 组合的字符开始,即 “->”
* 不能包含两个连续的 U+002D HYPHEN-MINUS 字符,即 “–”
* 不能以一个 U+002D HYPHEN-MINUS 字符结束,即 “-”
  • 必须以3个有序字符结束:U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN,即 “–>”

标准写法:

<!--Comment Text-->

错误的写法:

<!-->The Wrong Comment Text-->

<!--->The Wrong Comment Text-->

<!--The--Wrong--Comment Text-->

<!--The Wrong Comment Text--->

# 团队约定

# 单行注释

一般用于简单的描述,如某些状态描述、属性描述等 注释内容前后各一个空格字符,注释位于要注释代码的上面,单独占一行

推荐:

<!-- Comment Text --><div>...</div>

不推荐:

<div>...</div><!-- Comment Text -->	
	
<div><!-- Comment Text -->
    ...
</div>

# 模块注释

一般用于描述模块的名称以及模块开始与结束的位置 注释内容前后各一个空格字符, 表示模块开始, 表示模块结束,模块与模块之间相隔一行

推荐写法:

<!-- S Comment Text A -->	
<div class="mod_a">
    ...
</div>
<!-- E Comment Text A -->
	
<!-- S Comment Text B -->	
<div class="mod_b">
    ...
</div>
<!-- E Comment Text B -->

不推荐写法:

<!-- S Comment Text A -->
<div class="mod_a">
    ...
</div>
<!-- E Comment Text A -->
<!-- S Comment Text B -->	
<div class="mod_b">
    ...
</div>
<!-- E Comment Text B -->

嵌套模块注释

当模块注释内再出现模块注释的时候,为了突出主要模块,嵌套模块不再使用

<!-- S Comment Text -->
<!-- E Comment Text -->

而改用

<!-- /Comment Text -->

注释写在模块结尾标签底部,单独一行。

<!-- S Comment Text A -->
<div class="mod_a">
		
    <div class="mod_b">
        ...
    </div>
    <!-- /mod_b -->
    	
    <div class="mod_c">
    	...
    </div>
    <!-- /mod_c -->
		
</div>
<!-- E Comment Text A -->

# CSS规范

# 代码规范

# 编码规范

CSS样式表是一个序列通用字符集,传输和存储过程中,这些字符必须由支持 US-ASCII(例如 UTF-8, ISO 8859-x, SHIFT JIS 等)字符编码方式编译。

# 文档内嵌样式表编码

  • 当样式出现在其它文档,如 HTML 的 STYLE 标签或标签属性“style”,样式的编码由文档的决定。

# 文档外链样式表编码

文档外链样式表的编码可以由以下各项按照由高到低的优先级顺序决定:

  • HTTP “Content-Type” 字段参数 “charset”(或其它协议相似的参数)
  • BOM(byte-order mark)和(或)@charset
  • Link 中的元数据设置(如果有的话)
  • 引用样式表字符集或文档编码(如果有的话)
  • 假定为 UTF-8 编码

# 样式表编码

  • @charset规则一定要在样式文件的第一行首个字符位置开始,否则的话就会有机会让 BOM 设置生效(如果有设置 BOM 的话)而优于 @charset 作为样式表的编码
  • @charset ""; 一定要写上,并且用小写字母,不能出现转义符

# 团队约定

  • 样式文件必须写上 @charset 规则,并且一定要在样式文件的第一行首个字符位置开始写,编码名用 “UTF-8”
  • 字符 @charset “”; 都用小写字母,不能出现转义符,编码名允许大小混写
  • 考虑到在使用“UTF-8”编码情况下 BOM 对代码的污染和编码显示的问题,在可控范围下,坚决不使用 BOM。

推荐:

@charset "UTF-8";

.jdc{}

不推荐:

/**
 * @desc File Info
 * @author Author Name
 * @date 2015-10-10
 */
 
/* @charset规则不在文件首行首个字符开始 */
@charset "UTF-8";

.jdc{}
@CHARSET "UTF-8";
/* @charset规则没有用小写 */

.jdc{}
/* 无@charset规则 */
.jdc{}

# 代码风格

# 代码格式化

样式书写一般有两种:

一种是紧凑格式 (Compact)

.jdc{ display: block;width: 50px;}

一种是展开格式(Expanded)

.jdc{
    display: block;
    width: 50px;
}

# 团队约定

统一使用展开格式书写样式

# 代码大小写

样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。

推荐:

.jdc{
	display:block;
}

不推荐:

.JDC{
	DISPLAY:BLOCK;
}

# 选择器

  • 尽量少用通用选择器 *
  • 不使用 ID 选择器
  • 不使用无具体语义定义的标签选择器
/* 推荐 */
.jdc {}
.jdc li {}
.jdc li p{}

/* 不推荐 */
*{}
#jdc {}
.jdc div{}

# 代码缩进

统一使用四个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)

.jdc {
    width: 100%;
    height: 100%;
}

分号

每个属性声明末尾都要加分号;

.jdc {
    width: 100%;
    height: 100%;
}

代码易读性

左括号与类名之间一个空格,冒号与属性值之间一个空格

推荐:

.jdc {     width: 100%; }

不推荐:

.jdc{     width:100%;}

逗号分隔的取值,逗号之后一个空格

推荐:

.jdc {
    box-shadow: 1px 1px 1px #333, 2px 2px 2px #ccc;
}

不推荐:

.jdc {
    box-shadow: 1px 1px 1px #333,2px 2px 2px #ccc;
}

为单个css选择器或新申明开启新行

推荐:

.jdc, 
.jdc_logo, 
.jdc_hd {
    color: #ff0;
}
.nav{
    color: #fff;
}

不推荐:

.jdc,jdc_logo,.jdc_hd {
    color: #ff0;
}.nav{
    color: #fff;
}

颜色值 rgb() rgba() hsl() hsla() rect() 中不需有空格,且取值不要带有不必要的 0

推荐:

.jdc {
    color: rgba(255,255,255,.5);
}

不推荐:

.jdc {
    color: rgba( 255, 255, 255, 0.5 );
}

属性值十六进制数值能用简写的尽量用简写

推荐:

.jdc {
    color: #fff;
}

不推荐:

.jdc {
    color: #ffffff;
}

不要为 0 指明单位

推荐:

.jdc {
    margin: 0 10px;
}

不推荐:

.jdc {
    margin: 0px 10px;
}

# 属性值引号

css属性值需要用到引号时,统一使用单引号

/* 推荐 */
.jdc { 
	font-family: 'Hiragino Sans GB';
}

/* 不推荐 */
.jdc { 
	font-family: "Hiragino Sans GB";
}

# 属性书写顺序

建议遵循以下顺序:

  • 布局定位属性:display / position / float / clear / visibility / overflow
  • 自身属性:width / height / margin / padding / border / background
  • 文本属性:color / font / text-decoration / text-align / vertical-align / white- space / break-word
  • 其他属性(CSS3):content / cursor / border-radius / box-shadow / text-shadow / background:linear-gradient …
.jdc {
    display: block;
    position: relative;
    float: left;
    width: 100px;
    height: 100px;
    margin: 0 10px;
    padding: 20px 0;
    font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;
    color: #333;
    background: rgba(0,0,0,.5);
    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    -o-border-radius: 10px;
    -ms-border-radius: 10px;
    border-radius: 10px;
}

# CSS3浏览器私有前缀写法

CSS3 浏览器私有前缀在前,标准前缀在后

.jdc {
    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    -o-border-radius: 10px;
    -ms-border-radius: 10px;
    border-radius: 10px;
}

# 注释规范

  • 注释以字符 /* 开始,以字符 */ 结束
  • 注释不能嵌套

# 团队约定

# 单行注释

注释内容第一个字符和最后一个字符都是一个空格字符,单独占一行,行与行之间相隔一行

推荐:

/* Comment Text */
.jdc{}

/* Comment Text */
.jdc{}

不推荐:

/*Comment Text*/
.jdc{
	display: block;
}
.jdc{
	display: block;/*Comment Text*/
}

# 模块注释

注释内容第一个字符和最后一个字符都是一个空格字符,/* 与 模块信息描述占一行,多个横线分隔符-与*/占一行,行与行之间相隔两行

推荐:

/* Module A
---------------------------------------------------------------- */
.mod_a {}


/* Module B
---------------------------------------------------------------- */
.mod_b {}

不推荐:

/* Module A ---------------------------------------------------- */
.mod_a {}
/* Module B ---------------------------------------------------- */
.mod_b {}

# 文件信息注释

在样式文件编码声明 @charset 语句下面注明页面名称、作者、创建日期等信息

@charset "UTF-8";
/**
 * @desc File Info
 * @author Author Name
 * @date 2015-10-10
 */

# SASS规范

# 语法选用

SASS有两种语法格式,一种是 SCSS (Sassy CSS),另一种是缩进格式(Indented Syntax),有时称之为 Sass。

# SCSS

SCSS语法基于CSS语法扩展,每一个有效的 CSS 文件都是一个有效的具有相同含义的 SCSS 文件。

换种说法就是SCSS能识别大多数的 CSS hacks写法和浏览器前缀写法以及早期的 IE 滤镜写法,这种格式以.scss 作为扩展名。

# Sass

Sass 使用 “缩进”代替“花括号”表示属性属于某个选择器,用 “换行” 代替 “分号” 分隔属性,很多人认为这样做比 SCSS 更容易阅读,书写也更快速。

缩进格式也可以使用Sass的全部功能,只是与 SCSS 相比个别地方采取了不同的表达方式,具体请查看 the indented syntax reference。这种格式以 .sass 作为拓展名。

# 团队约定

考虑到 SCSS语法对CSS语法友好的兼容性和扩展性,我们在使用SASS编写样式的时候,统一使用 SCSS 语法。

# 编码格式

当在 Ruby1.9或更新的版本运行的时候,SASS 能识辨文档的字符编码。

SASS 遵循 CSS 规范去确定样式文件的编码,进而转回 Ruby 字符串编码。

这意味着SASS编译的时候会首先检测 BOM,然后到 @charset 声明,再到 Ruby 字符串编码,如果以上都没有设置,SASS 会认为文档的编码为 UTF-8

# 团队约定

严格遵守上面 “CSS规范” 中的 “编码规范” 更多关于 SASS 编码:SASS Encodings

# SASS注释规范

SASS支持 CSS 标准的多行注释 /* */,同时也支持单行注释 //。

多行注释在使用非 Compressed 模式进行编译后的输出文件中会保留下来,单行注释 // 侧会被移除 多行注释和单行注释在 SASS 编译后输出的压缩 CSS 文件都会被移除 当多行注释内容第一个字符是感叹号 “!” 的时候,即 /*! */,SASS

无论用哪一种编译方式编译注释都会保留 注释内容可以加入 SASS 变量

# 团队约定

SCSS 文件内 全部遵循 CSS 注释规范 不使用 /*! */ 注释方式 注释内不放 SASS 变量 标准的注释规范如下:

# 嵌套规范

选择器嵌套

/* CSS */
.jdc {}
body .jdc {}

/* SCSS */
.jdc {
    body & {}
}
/* CSS */
.jdc {}
.jdc_cover {}
.jdc_info {}
.jdc_info_name {}

/* SCSS */
.jdc {
    &_cover {}
    &_info {
        &_name {}
    }
}

属性嵌套

/* CSS */
.jdc {
    background-color: red;
    background-repeat: no-repeat;
    background-image: url(/img/icon.png);
    background-position: 0 0;
}

/* SCSS */
.jdc {
    background: {
        color: red;
        repeat: no-repeat;
        image: url(/img/icon.png);
        position: 0 0;
    }
}

变量

可复用属性尽量抽离为页面变量,易于统一维护

// CSS
.jdc {
    color: red;
    border-color: red;
}

// SCSS
$color: red;
.jdc {
    color: $color;
    border-color: $color;
}

混合(mixin)

根据功能定义模块,然后在需要使用的地方通过 @include调用,避免编码时重复输入代码段

// CSS
.jdc_1 {
    -webkit-border-radius: 5px;
    border-radius: 5px;
}
.jdc_2 {
    -webkit-border-radius: 10px;
    border-radius: 10px;
}

// SCSS
@mixin radius($radius:5px) {
    -webkit-border-radius: $radius;
    border-radius: $radius;
}
.jdc_1 {
    @include radius; //参数使用默认值
}
.jdc_2 {
    @include radius(10px);
}



// CSS
.jdc_1 {
    background: url(/img/icon.png) no-repeat -10px 0;
}
.jdc_2 {
    background: url(/img/icon.png) no-repeat -20px 0;
}

// SCSS
@mixin icon($x:0, $y:0) {
    background: url(/img/icon.png) no-repeat $x, $y;
}
.jdc_1 {
    @include icon(-10px, 0);
}
.jdc_2 {
    @include icon(-20px, 0);
}

占位选择器 %

如果不调用则不会有任何多余的 css 文件,占位选择器以 % 标识定义,通过@extend

//scss
%borderbox {
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
.jdc {
    @extend %borderbox;
}

extend 继承

// CSS
.jdc_1 {
    font-size: 12px;
    color: red;
}
.jdc_2 {
    font-size: 12px;
    color: red;
    font-weight: bold;
}

// SCSS
.jdc_1 {
    font-size: 12px;
    color: red;
}
.jdc_2 {
    @extend .jdc_1;
    font-weight: bold;
}

// 或者
%font_red {
    font-size: 12px;
    color: red;
}
.jdc_1 {
    @extend %font_red;
}
.jdc_2 {
    @extend %font_red;
    font-weight: bold;
}

for 循环

// CSS
.jdc_1 {background-position: 0 -20px;}
.jdc_2 {background-position: 0 -40px;}
.jdc_3 {background-position: 0 -60px;}

// SCSS
@for $i from 1 through 3 {
    .jdc_#{$i} {
        background-position: 0 (-20px) * $i;
    }
}

each 循环

// CSS
.jdc_list {
    background-image: url(/img/jdc_list.png);
}
.jdc_detail {
    background-image: url(/img/jdc_detail.png);
}

// SCSS
@each $name in list, detail {
    .jdc_#{$name} {
        background-image: url(/img/jdc_#{$name}.png);
    }
}


// CSS
.jdc_list {
    background-image: url(/img/jdc_list.png);
    background-color: red;
}
.jdc_detail {
    background-image: url(/img/jdc_detail.png);
    background-color: blue;
}

// SCSS
@each $name, $color in (list, red), (detail, blue) {
    .jdc_#{$name} {
        background-image: url(/img/jdc_#{$name}.png);
        background-color: $color;
    }
}

function 函数

@function pxToRem($px) {
    @return $px / 10px * 1rem;
}
.jdc {
    font-size: pxToRem(12px);
}

运算规范 运算符之间空出一个空格

.jdc {
    width: 100px - 50px;
    height: 30px / 5;
}

注意运算单位,单位同时参与运算,所以 10px 不等于10,乘除运算时需要特别注意

// 正确的运算格式
.jdc {
    width: 100px - 50px;
    width: 100px + 50px;
    width: 100px * 2;
    width: 100px / 2;
}

# JS规范

# 语言规范

JavaScript 是一种客户端脚本语言,这里列出了编写 JavaScript 时需要遵守的规则。

# 类型

# 基本类型

  • 字符串
  • 数值
  • 布尔类型
  • null
  • undefined
const foo = 1
let bar = foo

bar = 9

console.log(foo, bar) // 1, 9

# 复杂类型

  • object
  • array
  • function
const foo = [1, 2, 3]
const bar = foo

bar[0] = 9

console.log(foo[0], bar[0]) // 9, 9

# 引用

const 和 let 都是块级作用域,var 是函数级作用域

  • 对所有引用都使用 const,不要使用 var
// bad
var a = 1
var b = 2

// good
const a = 1
const b = 2
  • 如果引用是可变动的,则使用 let
// bad
var count = 1
if (count < 10) {
  count += 1
}

// good
let count = 1
if (count < 10) {
  count += 1
}

# 对象

  • 请使用字面量值创建对象
// bad
const a = new Object{}

// good
const a = {}
  • 别使用保留字作为对象的键值,这样在 IE8 下不会运行
// bad
const a = {
  default: {},  // default 是保留字
  common: {}
}

// good
const a = {
  defaults: {},
  common: {}
}
  • 请使用对象方法的简写方式
// bad
const item = {
  value: 1,

  addValue: function (val) {
    return item.value + val
  }
}

// good
const item = {
  value: 1,

  addValue(val) {
    return item.value + val
  }
}
  • 请使用对象属性值的简写方式
const job = 'FrontEnd'

// bad
const item = {
  job: job
}

// good
const item = {
  job
}
  • 对象属性值的简写方式要和声明式的方式分组
const job = 'FrontEnd'
const department = 'JDC'

// bad
const item = {
  sex: 'male',
  job,
  age: 25,
  department
}

// good
const item = {
  job,
  department,
  sex: 'male',
  age: 25
}

# 数组

  • 请使用字面量值创建数组
// bad
const items = new Array()

// good
const items = []
  • 向数组中添加元素时,请使用 push 方法
const items = []

// bad
items[items.length] = 'test'

// good
items.push('test')
  • 使用拓展运算符 ... 复制数组
// bad
const items = []
const itemsCopy = []
const len = items.length
let i

// bad
for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i]
}

// good
itemsCopy = [...items]
  • 使用数组的 map 等方法时,请使用
// good
[1, 2, 3].map(x => {
  const y = x + 1
  return x * y
})

// good
[1, 2, 3].map(x => x + 1)

// bad
const flat = {}
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
  const flatten = memo.concat(item)
  flat[index] = flatten
})

// good
const flat = {}
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
  const flatten = memo.concat(item)
  flat[index] = flatten
  return flatten
})

// bad
inbox.filter((msg) => {
  const { subject, author } = msg
  if (subject === 'Mockingbird') {
    return author === 'Harper Lee'
  } else {
    return false
  }
})

// good
inbox.filter((msg) => {
  const { subject, author } = msg
  if (subject === 'Mockingbird') {
    return author === 'Harper Lee'
  }

  return false
})

# 解构赋值

  • 当需要使用对象的多个属性时,请使用解构赋值
// bad
function getFullName (user) {
  const firstName = user.firstName
  const lastName = user.lastName

  return `${firstName} ${lastName}`
}

// good
function getFullName (user) {
  const { firstName, lastName } = user

  return `${firstName} ${lastName}`
}

// better
function getFullName ({ firstName, lastName }) {
  return `${firstName} ${lastName}`
}
  • 当需要使用数组的多个值时,请同样使用解构赋值
const arr = [1, 2, 3, 4]

// bad
const first = arr[0]
const second = arr[1]

// good
const [first, second] = arr
  • 函数需要回传多个值时,请使用对象的解构,而不是数组的解构
// bad
function doSomething () {
  return [top, right, bottom, left]
}

// 如果是数组解构,那么在调用时就需要考虑数据的顺序
const [top, xx, xxx, left] = doSomething()

// good
function doSomething () {
  return { top, right, bottom, left }
}

// 此时不需要考虑数据的顺序
const { top, left } = doSomething()

# 字符串

  • 字符串统一使用单引号的形式 ''
// bad
const department = "JDC"

// good
const department = 'JDC'
  • 字符串太长的时候,请不要使用字符串连接符换行 \,而是使用 +
const str = '凹凸实验室 凹凸实验室 凹凸实验室' +
  '凹凸实验室 凹凸实验室 凹凸实验室' +
  '凹凸实验室 凹凸实验室'
  • 程序化生成字符串时,请使用模板字符串
const test = 'test'

// bad
const str = ['a', 'b', test].join()

// bad
const str = 'a' + 'b' + test

// good
const str = `ab${test}`

# 函数

请使用函数声明,而不是函数表达式

// bad
const foo = function () {
  // do something
}

// good
function foo () {
  // do something
}
  • 不要在非函数代码块中声明函数
// bad
if (isUse) {
  function test () {
    // do something
  }
}

// good
let test
if (isUse) {
  test = () => {
    // do something
  }
}
  • 不要使用 arguments,可以选择使用 ...

arguments 只是一个类数组,而 ... 是一个真正的数组

// bad
function test () {
  const args = Array.prototype.slice.call(arguments)
  return args.join('')
}

// good
function test (...args) {
  return args.join('')
}
  • 不要更改函数参数的值
// bad
function test (opts) {
  opts = opts || {}
}

// good
function test (opts = {}) {
  // ...
}

# 原型

  • 使用 class,避免直接操作 prototype
// bad
function Queue (contents = []) {
  this._queue = [..contents]
}
Queue.prototype.pop = function () {
  const value = this._queue[0]
  this._queue.splice(0, 1)
  return value
}

// good
class Queue {
  constructor (contents = []) {
    this._queue = [...contents]
  }

  pop () {
    const value = this._queue[0]
    this._queue.splice(0, 1)
    return value
  }
}

# 模块

  • 使用标准的 ES6 模块语法 import 和 export
// bad
const util = require('./util')
module.exports = util

// good
import Util from './util'
export default Util

// better
import { Util } from './util'
export default Util
  • 不要使用 import 的通配符 *,这样可以确保你只有一个默认的 export
// bad
import * as Util from './util'

// good
import Util from './util'

# 迭代器

  • 不要使用 iterators
const numbers = [1, 2, 3, 4, 5]

// bad
let sum = 0
for (let num of numbers) {
  sum += num
}

// good
let sum = 0
numbers.forEach(num => sum += num)

// better
const sum = numbers.reduce((total, num) => total + num, 0)

# 对象属性

  • 使用 . 来访问对象属性
const joke = {
  name: 'haha',
  age: 28
}

// bad
const name = joke['name']

// good
const name = joke.name

# 变量声明

声明变量时,请使用const、let关键字,如果没有写关键字,变量就会暴露在全局上下文中,这样很可能会和现有变量冲突,另外,也很难明确该变量的作用域是什么。

这里推荐使用const来声明变量,我们需要避免全局命名空间的污染。

// bad
demo = new Demo()

// good
const demo = new Demo()
  • 将所有的 const 和 let 分组
// bad
let a
const b
let c
const d
let e

// good
const b
const d
let a
let c
let e

# Hosting

  • var 存在变量提升的情况,即 var 声明会被提升至该作用域的顶部,但是他们的赋值并不会。
  • 而 const 和 let 并不存在这种情况,他们被赋予了 Temporal Dead Zones, TDZ
function example () {
  console.log(notDefined)   // => throws a ReferenceError
}

function example () {
  console.log(declareButNotAssigned)  // => undefined
  var declaredButNotAssigned = true
}

function example () {
  let declaredButNotAssigned
  console.log(declaredButNotAssigned)   // => undefined
  declaredButNotAssigned = true
}

function example () {
  console.log(declaredButNotAssigned)   // => throws a ReferenceError
  console.log(typeof declaredButNotAssigned)  // => throws a ReferenceError
  const declaredButNotAssigned = true
}
  • 匿名函数的变量名会提升,但函数内容不会
function example () {
  console.log(anonymous)  // => undefined

  anonymous()

  var anonymous = function () {
    console.log('test')
  }
}
  • 命名的函数表达式的变量名会被提升,但函数名和函数函数内容并不会
function example() {
  console.log(named)  // => undefined

  named()   // => TypeError named is not a function

  superPower()  // => ReferenceError superPower is not defined

  var named = function superPower () {
    console.log('Flying')
  }
}

function example() {
  console.log(named)  // => undefined

  named()   // => TypeError named is not a function

  var named = function named () {
    console.log('named')
  }
}

# 分号

  • 我们遵循Standard的规范,不使用分号。

关于应不应该使用分号的讨论有很多,本规范认为非必要的时候,应该不使用分号,好的 JS 程序员应该清楚场景下是一定要加分号的,相信你也是名好的开发者。

一行开头是括号或者方括号的时候加上分号,其他时候全部不需要。

因为真正会导致上下行解析出问题的token有5个:括号,方括号,正则开头的斜杠,加号,减号。

// bad
const test = 'good';
(function () {
  const str = 'hahaha';
})()

// good
const test = 'good'
;(() => {
  const str = 'hahaha'
})();

# 标准特性

为了代码的可移植性和兼容性,我们应该最大化的使用标准方法,例如优先使用 string.charAt(3) 而不是 string[3]

# eval()

由于 eval 方法比较evil,所以我们约定禁止使用该方法

# with() {}

由于 with 方法会产生神奇的作用域,所以我们也是禁止使用该方法的

# for-in 循环

推荐使用for in语法,但是在对对象进行操作时,容易忘了检测 hasOwnProperty(key),所以我们启用了 ESLint 的 guard-for-in 选项

对数组进行 for in的时候,顺序是不固定的。对数组我们采用for of

# 修改内置对象的原型

不要修改内置对象,如 Object 和 Array

# 代码规范

# 编码规范

本章是传统意义上的Style Guideline,目的是统一一些相对主观化的代码风格。

# 单行代码块

在单行代码块中使用空格

不推荐

function foo () {return true}
if (foo) {bar = 0}

推荐

function foo () { return true }
if (foo) { bar = 0 }

# 大括号风格

在编程过程中,大括号风格与缩进风格紧密联系,用来描述大括号相对代码块位置的方法有很多。在 JavaScript 中,主要有三种风格,如下:

  • One True Brace Style
if (foo) {
  bar()
} else {
  baz()
}
  • Stroustrup
if (foo) {
  bar()
}
else {
  baz()
}
  • Allman
if (foo)
{
  bar()
}
else
{
  baz()
}

我们团队约定使用 One True Brace Style 风格

# 变量命名

当命名变量时,主流分为驼峰式命名(variableName)和下划线命名(variable_name)两大阵营。

团队约定使用驼峰式命名

# 拖尾逗号

在 ECMAScript5里面,对象字面量中的拖尾逗号是合法的,但在IE8(非IE8文档模式)下,当出现拖尾逗号,则会抛出错误。

拖尾逗号的例子:

var foo = {
  name: 'foo',
  age: '22',
}

拖尾逗号的好处是,简化了对象和数组添加或删除元素,我们只需要修改新增的行即可,并不会增加差异化的代码行数。

因为拖尾逗号有好也有不好,所以团队约定允许在最后一个元素或属性与闭括号 ] 或 } 在不同行时,可以(但不要求)使用拖尾逗号。

当在同一行时,禁止使用拖尾逗号。

# 逗号空格

逗号前后的空格可以提高代码的可读性,团队约定在逗号后面使用空格,逗号前面不加空格。

不推荐

var foo = 1,bar = 2
var foo = 1 , bar = 2
var foo = 1 ,bar = 2

推荐

var foo = 1, bar = 2

# 逗号风格

逗号分隔列表时,在 JavaScript 中主要有两种逗号风格:标准风格,逗号放置在当前行的末尾逗号前置风格,逗号放置在下一行的开始位置

团队约定使用标准风格

不推荐

var foo = 1
,
bar = 2

var foo = 1
, bar = 2

var foo = ['name'
          , 'age']
          

推荐

var foo = 1,
    bar = 2

var foo = ['name',
            'age']

# 计算属性的空格

团队约定在对象的计算属性内,禁止使用空格

不推荐

obj['foo' ]
obj[ 'foo']
obj[ 'foo' ]

推荐

obj['foo']

# 拖尾换行

在非空文件中,存在拖尾换行是一个常见的 UNIX 风格,它的好处是可以方便在串联和追加文件时不会打断 Shell 的提示。

在日常的项目中,保留拖尾换行的好处是,可以减少版本控制时的代码冲突。

不推荐

function func () {
  // do something
}

推荐

function func () {
  // do something
}
  // 此处是新的一行

可以通过 .editorconfig 添加 EOL

# 函数调用

为了避免语法错误,团队约定在函数调用时,禁止使用空格

不推荐

fn ()
fn
()

推荐

fn()

# 缩进

代码保持一致的缩进,是作为工程师的职业素养。但缩进用两个空格,还是四个空格,是用 Tab还是空格呢?这样的争论太多了,也得不出答案。

本规范结合了市面上优秀的开源项目,姑且约定使用空格来缩进,而且缩进使用两个空格。

那是不是不能使用Tab进行缩进了?我们可以通过配置 .editorconfig ,将 Tab 自动转换为空格。

# 对象字面量的键值缩进

团队约定对象字面量的键和值之间不能存在空格,且要求对象字面量的冒号和值之间存在一个空格

不推荐

var obj = { 'foo' : 'haha' }

推荐

var obj = { 'foo': 'haha' }

# 构造函数首字母大写

在 JavaScript中new操作符用来创建某个特定类型的对象的一个实例,该类型的对象是由一个构造函数表示的。

由于构造函数只是常规函数,唯一区别是使用new来调用。

所以我们团队约定构造函数的首字母要大小,以此来区分构造函数和普通函数。

不推荐

var fooItem = new foo()

推荐

var fooItem = new Foo()

# 构造函数的参数

在 JavaScript中,通过new调用构造函数时,如果不带参数,可以省略后面的圆括号。但这样会造成与整体的代码风格不一致,所以团队约定使用圆括号。

不推荐

var person = new Person

推荐

var person = new Person()

# 链式调用

链式调用如果放在同一行,往往会造成代码的可读性差,但有些时候,短的链式调用并不会影响美观。

所以本规范约定一行最多只能有四个链式调用,超过就要求换行。

# 空行

空白行对于分离代码逻辑有帮助,但过多的空行会占据屏幕的空间,影响可读性。

团队约定最大连续空行数为 2

# 链式赋值

链式赋值容易造成代码的可读性差,所以团队约定禁止使用链式赋值

不推荐

var a = b = c = 1

推荐

var a = 1
var b = 1
var c = 1

# 变量声明

JavaScript允许在一个声明中,声明多个变量。团队约定在声明变量时,一个声明只能有一个变量

不推荐

var a, b, c

推荐

var a
var b
var c

# 分号

JavaScript在所有类C语言中是比较独特的,它不需要在每个语句的末尾有分号。

在很多情况下,JavaScript引擎可以确定一个分号应该在什么位置然后自动添加它。此特征被称为自动分号插入(ASI),被认为是 JavaScript 中较为有争议的特征。

团队中对于是否应该使用分号,也有许多争论,本规范推荐不使用分号,因为我们认为好的工程师应该知道什么时候该加,什么时候不该加。

# 代码块空格

一致性是任何风格指南的重要组成部分。虽然在哪里放置块的开括号纯属个人偏好,但在整个项目中应该保持一致。

不一致的风格将会分散读者阅读代码的注意力。

团队约定代码块前要添加空格

不推荐

if (a){
  b()
}

function a (){}

推荐

if (a) {
  b()
}

function a () {}

# 函数声明的空格

当格式化一个函数,函数名或 function 关键字与左括号之间允许有空白。

命名函数要求函数名和function关键字之间有空格,但是匿名函数要求不加空格。

团队约定函数括号前要加空格

不推荐

function func(x) {
  // ...
}

推荐

function func (x) {
  // ...
}

# 操作符的空格

团队约定操作符前后都需要添加空格

不推荐

var sum = 1+2

推荐

var sum = 1 + 2

# BOM

Unicode 字节顺序标记 (BOM) 用来指定代码单元是高字节序还是低字节序。也就是说,是高位在前还是低位在前。

UTF-8 不需要BOM来表明字节顺序,因为单个字节并不影响字节顺序。

相信不少同学遇到过BOM的坑,这里不多说了,切记不要使用windows的记事本改代码!

本文整理自凹凸实验室,更多详细内容请移步官方文档

凹凸实验室