为了方便团队其他人员的阅读本人代码,减少团队交流成本,提高工作效率。代码规范很重要,公司这段时间尤其对这一块重视。
本人对这块的学习改正重点为如下:
HTML
一,class和ID的命名问题:
1.应该以内容和功能命名,不要以表现形式命名。
2.字母为小写,多个字母时用中划线-分隔
3.ID为js hook,避免使用空的class样式
二,ID统一使用双引号
三,标签语意化
标签 | 语义 |
---|---|
<p> | 段落 |
<h1> <h2> <h3> ... | 标题 |
<ul> | 无序列表 |
<ol> | 有序列表 |
<blockquote> | 大段引用 |
<cite> | 一般引用 |
<b> | 为样式加粗而加粗 |
<storng> | 为强调内容而加粗 |
<i> | 为样式倾斜而倾斜 |
<em> | 为强调内容而倾斜 |
code | 代码标识 |
abbr | 缩写 |
可以看看这个百度文库里面的优秀文件:https://wenku.baidu.com/view/0a8d3774f242336c1eb95ea9.html
四,HEAD
HEAD模版<!DOCTYPE html>
<html lang="zh-cmn-Hans"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Style Guide</title>
<!-- SEO优化 -->
<meta name="description" content="不超过150个字符"> <meta name="keywords" content=""> <meta name="author" content="name, email@gmail.com"> <!-- 为移动设备添加 viewport --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- iOS 图标 --> <link rel="apple-touch-icon-precomposed" href="/apple-touch-icon-57x57-precomposed.png"> <link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" /> <link rel="shortcut icon" href="path/to/favicon.ico"> </head>
1.语言属性的设置
<!-- 中文 --> <html lang="zh-Hans"> <!-- 简体中文 --> <html lang="zh-cmn-Hans"> <!-- 繁体中文 --> <html lang="zh-cmn-Hant"> <!-- English --> <html lang="en">
2.字符编码
utf-8
3.IE兼容模式
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
4.SEO优化 (搜索引擎优化)
<head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <!-- SEO --> <title>Style Guide</title> <meta name="keywords" content="your keywords"> <meta name="description" content="your description"> <meta name="author" content="author,email address"> </head>
5.viewport
<meta name="viewport" content="width=device-width, initial-scale=1.0">
viewport
: 一般指的是浏览器窗口内容区的大小,不包含工具条、选项卡等内容;width
: 浏览器宽度,输出设备中的页面可见区域宽度;device-width
: 设备分辨率宽度,输出设备的屏幕可见宽度;initial-scale
: 初始缩放比例;maximum-scale
: 最大缩放比例;
6.favicon
link指定favicon.ico文件
<link rel="shortcut icon" href="path/to/favicon.ico">
CSS
良好的注释是非常重要的。请留出时间来描述组件(component)的工作方式、局限性和构建它们的方法。不要让你的团队其它成员 来猜测一段不通用或不明显的代码的目的。
汇总:
- 以
Components
的角度思考,以两个单词命名(.screenshot-image
) Components
中的Elements
,以一个单词命名(.blog-post .title
)Variants
,以中划线-
作为前缀(.shop-banner.-with-icon
)Components
可以互相嵌套- 记住,你可以通过继承让事情变得更简单
一,class和ID命名
- 使用语义化、通用的命名方式;
- 使用连字符 - 作为 ID、Class 名称界定符,不要驼峰命名法和下划线;
- 避免选择器嵌套层级过多,尽量少于 3 级;
- 避免选择器和 Class、ID 叠加使用;
避免class,ID和选择器混合式使用,若改了class名称还要去改CSS代码,不利于后期的维护
二,声明块格式
- 选择器分组时,保持独立的选择器占用一行;
- 声明块的左括号
{
前添加一个空格; - 声明块的右括号
}
应单独成行; - 声明语句中的
:
后应添加一个空格; - 声明语句应以分号
;
结尾; - 一般以逗号分隔的属性值,每个逗号后应添加一个空格;
rgb()
、rgba()
、hsl()
、hsla()
或rect()
括号内的值,逗号分隔,但逗号后不添加一个空格;- 对于属性值或颜色参数,省略小于 1 的小数前面的 0 (例如,
.5
代替0.5
;-.5px
代替-0.5px
); - 十六进制值应该全部小写和尽量简写,例如,
#fff
代替#ffffff
; - 避免为 0 值指定单位,例如,用
margin: 0;
代替margin: 0px;
;
三,声明顺序
相关属性应为一组,推荐的样式编写顺序
- Positioning(由于定位(positioning)可以从正常的文档流中移除元素,并且还能覆盖盒模型(box model)相关的样式,因此排在首位)
- Box model(盒模型决定了组件的尺寸和位置,因此排在第二位)
- Typographic(排版相关)
- Visual(视觉)
- Other(其他)
四,引号的使用
url()
、属性选择符、属性值使用双引号。
五,媒体查询(Media query)的位置
将媒体查询放在尽可能相关规则的附近。不要将他们打包放在一个单一样式文件中或者放在文档底部。如果你把他们分开了,将来只会被大家遗忘。
六,不要使用 @import
七,Components
最少以两个单词命名,通过 -
分离
- 点赞按钮 (
.like-button
) - 搜索框 (
.search-form
) - 文章卡片 (
.article-card
)
八,Elements
是 Components
中的元素 Elements 命名就用一个单词;
.search-form { > .field { /* ... */ } > .action { /* ... */ } }
对于倘若需要两个或以上单词表达的 Elements
类名,不应使用中划线和下划线连接,应直接连接。
.profile-box { > .firstname { /* ... */ } > .lastname { /* ... */ } > .avatar { /* ... */ } }
任何时候尽可能使用 classnames
。标签选择器在使用上没有问题,但是其性能上稍弱,并且表意不明确。避免使用标签选择器。
倘若你需要为组件设置定位,应将在组件的上下文(父元素)中进行处理,比如以下例子中,将 widths
和 floats
应用在 list component(.article-list)
当中,而不是 component(.article-card)
自身。
当出现多个嵌套的时候容易失去控制,应保持不超过一个嵌套。
关于CSS的性能优化
一,慎重选择高消耗的样式
- box-shadows
- border-radius
- transparency(透明)
- transforms(动画)
- CSS filters(滤镜 性能杀手)
二,避免重排列
- width
- height
- padding
- margin
- display
- border-width
- position
- top
- left
- right
- bottom
- font-size
- float
- text-align
- overflow-y
- font-weight
- overflow
- font-family
- line-height
- vertical-align
- clear
- white-space
- min-height
三,正确的使用display属性
Display 属性会影响页面的渲染,请合理使用。
-
display: inline后不应该再使用 width、height、margin、padding 以及 float;
-
display: inline-block 后不应该再使用 float;
-
display: block 后不应该再使用 vertical-align;
-
display: table-* 后不应该再使用 margin 或者 float;
四,不滥用float
五,动画性能的优化
动画的基本概念:
- 帧:在动画过程中,每一幅静止画面即为一“帧”;
- 帧率:即每秒钟播放的静止画面的数量,单位是fps(Frame per second);
- 帧时长:即每一幅静止画面的停留时间,单位一般是ms(毫秒);
- 跳帧(掉帧/丢帧):在帧率固定的动画中,某一帧的时长远高于平均帧时长,导致其后续数帧被挤压而丢失的现象。
一般浏览器的渲染刷新频率是 60 fps,所以在网页当中,帧率如果达到 50-60 fps 的动画将会相当流畅,让人感到舒适。
- 如果使用基于 javaScript 的动画,尽量使用 requestAnimationFrame. 避免使用 setTimeout, setInterval.
- 避免通过类似 jQuery animate()-style 改变每帧的样式,使用 CSS 声明动画会得到更好的浏览器优化。
- 使用 translate 取代 absolute 定位就会得到更好的 fps,动画会更顺滑。
六,多利用硬件能力,如通过 3D 变形开启 GPU 加速
一般在 Chrome 中,3D或透视变换(perspective transform)CSS属性和对 opacity 进行 CSS 动画会创建新的图层,在硬件加速渲染通道的优化下,GPU 完成 3D 变形等操作后,将图层进行复合操作(Compesite Layers),从而避免触发浏览器大面积重绘和重排。
七,提升CSS选择器的性能
理解了CSS选择器从右到左匹配的机制后,明白只要当前选择符的左边还有其他选择符,样式系统就会继续向左移动,直到找到和规则匹配的选择符,或者因为不匹配而退出。我们把最右边选择符称之为关键选择器。
1、避免使用通用选择器
2、避免使用标签或 class 选择器限制 id 选择器
3、避免使用标签限制 class 选择器
4、避免使用多层标签选择器。使用 class 选择器替换,减少css查找
/* Not recommended */ treeitem[mailfolder="true"] > treerow > treecell {…} /* Recommended */ .treecell-mailfolder {…}
5、避免使用子选择器
/* Not recommended */ treehead treerow treecell {…} /* Recommended */ treehead > treerow > treecell {…} /* Much to recommended */ .treecell-header {…}
6、使用继承
/* Not recommended */ #bookmarkMenuItem > .menu-left { list-style-image: url(blah) } /* Recommended */ #bookmarkMenuItem { list-style-image: url(blah) }
JavaScript
一,注释
原则:
- As short as possible(如无必要,勿增注释):尽量提高代码本身的清晰性、可读性。
- As long as necessary(如有必要,尽量详尽):合理的注释、空行排版等,可以让代码更易阅读、更具美感。
1. 单行注释
必须独占一行。//
后跟一个空格,缩进与下一行被注释说明的代码一致。
2. 多行注释
避免使用 /*...*/
这样的多行注释。有多行注释内容时,使用多个单行注释。
3. 函数/方法注释
- 函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。;
- 参数和返回值注释必须包含类型信息和说明;
- 当函数是内部函数,外部不可访问时,可以使用 @inner 标识;
/** * 函数描述 * * @param {string} p1 参数1的说明 * @param {string} p2 参数2的说明,比较长 * 那就换行了. * @param {number=} p3 参数3的说明(可选) * @return {Object} 返回值描述 */ function foo(p1, p2, p3) { var p3 = p3 || 10; return { p1: p1, p2: p2, p3: p3 }; }
4. 文件注释
文件注释用于告诉不熟悉这段代码的读者这个文件中包含哪些东西。 应该提供文件的大体内容, 它的作者, 依赖关系和兼容性信息。如下:
/** * @fileoverview Description of file, its uses and information * about its dependencies. * @author user@meizu.com (Firstname Lastname) * Copyright 2009 Meizu Inc. All Rights Reserved. */
二,命名
变量
- 变量使用‘驼峰’命名法
- 私有属性、变量和方法以下划线 _ 开头。
- 常量, 使用全部字母大写,单词间下划线分隔的命名方式。
函数
函数:
- 函数, 使用 Camel 命名法。
- 函数的参数, 使用 Camel 命名法。
类
- 类, 使用 Pascal 命名法
- 类的 方法 / 属性, 使用 Camel 命名法
枚举属性
- 枚举变量 使用 Pascal 命名法。
- 枚举的属性, 使用全部字母大写,单词间下划线分隔的命名方式。
由多个单词组成的 缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致。
三,命名语法
- 类名,使用名词。
- 函数名,使用动宾短语。
- boolean 类型的变量使用 is 或 has 开头。
- Promise 对象用动宾短语的进行时表达。
四,接口命名规范
- 可读性强,见名晓义;
- 尽量不与 jQuery 社区已有的习惯冲突;
- 尽量写全。不用缩写,除非是下面列表中约定的;(变量以表达清楚为目标,uglify 会完成压缩体积工作)
常用词 | 说明 |
---|---|
options | 表示选项,与 jQuery 社区保持一致,不要用 config, opts 等 |
active | 表示当前,不要用 current 等 |
index | 表示索引,不要用 idx 等 |
trigger | 触点元素 |
triggerType | 触发类型、方式 |
context | 表示传入的 this 对象 |
object | 推荐写全,不推荐简写为 o, obj 等 |
element | 推荐写全,不推荐简写为 el, elem 等 |
length | 不要写成 len, l |
prev | previous 的缩写 |
next | next 下一个 |
constructor | 不能写成 ctor |
easing | 示动画平滑函数 |
min | minimize 的缩写 |
max | maximize 的缩写 |
DOM | 不要写成 dom, Dom |
.hbs | 使用 hbs 后缀表示模版 |
btn | button 的缩写 |
link | 超链接 |
title | 主要文本 |
img | 图片路径(img标签src属性) |
dataset | html5 data-xxx 数据接口 |
theme | 主题 |
className | 类名 |
classNameSpace | class 命名空间 |
五,True 和 False 布尔表达式
类型检测优先使用 typeof。对象类型检测使用 instanceof。null 或 undefined 的检测使用 == null。
下面的布尔表达式都返回 false:
- null
- undefined
- '' 空字符串
- 0 数字0
但小心下面的, 可都返回 true:
- '0' 字符串0
- [] 空数组
- {} 空对象
六,不要在 Array 上使用 for-in 循环
for-in 循环只用于 object/map/hash
的遍历, 对 Array
用 for-in 循环有时会出错. 因为它并不是从 0 到 length - 1 进行遍历, 而是所有出现在对象及其原型链的键值。
// Not recommended function printArray(arr) { for (var key in arr) { print(arr[key]); } } printArray([0,1,2,3]); // This works. var a = new Array(10); printArray(a); // This is wrong. a = document.getElementsByTagName('*'); printArray(a); // This is wrong. a = [0,1,2,3]; a.buhu = 'wine'; printArray(a); // This is wrong again. a = new Array; a[3] = 3; printArray(a); // This is wrong again. // Recommended function printArray(arr) { var l = arr.length; for (var i = 0; i < l; i++) { print(arr[i]); } }
七,二元和三元操作符
操作符始终写在前一行, 以免分号的隐式插入产生预想不到的问题。
var x = a ? b : c; var y = a ? longButSimpleOperandB : longButSimpleOperandC; var z = a ? moreComplicatedB : moreComplicatedC;
.
操作符也是如此:
var x = foo.bar(). doSomething(). doSomethingElse();
八,条件(三元)操作符(?:)
三元操作符用于替代 if 条件判断语句。
// Not recommended if (val != 0) { return foo(); } else { return bar(); } // Recommended return val ? foo() : bar();
九,&& 和 ||
二元布尔操作符是可短路的, 只有在必要时才会计算到最后一项。
// Not recommended function foo(opt_win) { var win; if (opt_win) { win = opt_win; } else { win = window; } // ... } if (node) { if (node.kids) { if (node.kids[index]) { foo(node.kids[index]); } } } // Recommended function foo(opt_win) { var win = opt_win || window; // ... } var kid = node && node.kids && node.kids[index]; if (kid) { foo(kid); }
jQuery规范
一,使用最新版本的 jQuery
最新版本的 jQuery 会改进性能和增加新功能,若不是为了兼容旧浏览器,建议使用最新版本的 jQuery。以下是三条常见的 jQuery 语句,版本越新,性能越好
$('.elem') $('.elem', context) context.find('.elem')
分别使用 1.4.2、1.4.4、1.6.2 三个版本测试浏览器在一秒内能够执行多少次,结果 1.6.2 版执行次数远超两个老版本。
二,jQuery 变量
- 存放 jQuery 对象的变量以
$
开头; - 将 jQuery 选择器返回的对象缓存到本地变量中复用;
- 使用驼峰命名变量;
var $myDiv = $("#myDiv"); $myDiv.click(function(){...});
三,选择器
- 尽可能的使用 ID 选择器,因为它会调用浏览器原生方法
document.getElementById
查找元素。当然直接使用原生document.getElementById
方法性能会更好; - 在父元素中选择子元素使用
.find()
方法性能会更好, 因为 ID 选择器没有使用到 Sizzle 选择器引擎来查找元素;
// Not recommended var $productIds = $("#products .class"); // Recommended var $productIds = $("#products").find(".class");
四,DOM 操作
- 当要操作 DOM 元素的时候,尽量将其分离节点,操作结束后,再插入节点;
- 使用字符串连接或
array.join
要比.append()
性能更好;
var $myList = $("#list-container > ul").detach(); //...a lot of complicated things on $myList $myList.appendTo("#list-container");
// Not recommended var $myList = $("#list"); for(var i = 0; i < 10000; i++){ $myList.append("<li>"+i+"</li>"); } // Recommended var $myList = $("#list"); var list = ""; for(var i = 0; i < 10000; i++){ list += "<li>"+i+"</li>"; } $myList.html(list); // Much to recommended var array = []; for(var i = 0; i < 10000; i++){ array[i] = "<li>"+i+"</li>"; } $myList.html(array.join(''));
五,事件
- 如果需要,对事件使用自定义的
namespace
,这样容易解绑特定的事件,而不会影响到此 DOM 元素的其他事件监听; - 对 Ajax 加载的 DOM 元素绑定事件时尽量使用事件委托。事件委托允许在父元素绑定事件,子代元素可以响应事件,也包括 Ajax 加载后添加的子代元素;
$("#myLink").on("click.mySpecialClick", myEventHandler);
$("#myLink").unbind("click.mySpecialClick");
// Not recommended $("#list a").on("click", myClickHandler); // Recommended $("#list").on("click", "a", myClickHandler);
六,链式写法
- 尽量使用链式写法而不是用变量缓存或者多次调用选择器方法;
- 当链式写法超过三次或者因为事件绑定变得复杂后,使用换行和缩进保持代码可读性;
$("#myDiv").addClass("error").show();
$("#myLink") .addClass("bold") .on("click", myClickHandler) .on("mouseover", myMouseOverHandler) .show();
七,其他
- 多个参数使用对象字面量存储;
- 不要将 CSS 写在 jQuery 里面;
- 正则表达式仅准用 .test() 和 .exec() 。不准用 "string".match() ;
八,jQuery插件模版
// jQuery Plugin Boilerplate // A boilerplate for jumpstarting jQuery plugins development // version 1.1, May 14th, 2011 // by Stefan Gabos // remember to change every instance of "pluginName" to the name of your plugin! (function($) { // here we go! $.pluginName = function(element, options) { // plugin's default options // this is private property and is accessible only from inside the plugin var defaults = { foo: 'bar', // if your plugin is event-driven, you may provide callback capabilities // for its events. execute these functions before or after events of your // plugin, so that users may customize those particular events without // changing the plugin's code onFoo: function() {} } // to avoid confusions, use "plugin" to reference the // current instance of the object var plugin = this; // this will hold the merged default, and user-provided options // plugin's properties will be available through this object like: // plugin.settings.propertyName from inside the plugin or // element.data('pluginName').settings.propertyName from outside the plugin, // where "element" is the element the plugin is attached to; plugin.settings = {} var $element = $(element), // reference to the jQuery version of DOM element element = element; // reference to the actual DOM element // the "constructor" method that gets called when the object is created plugin.init = function() { // the plugin's final properties are the merged default and // user-provided options (if any) plugin.settings = $.extend({}, defaults, options); // code goes here } // public methods // these methods can be called like: // plugin.methodName(arg1, arg2, ... argn) from inside the plugin or // element.data('pluginName').publicMethod(arg1, arg2, ... argn) from outside // the plugin, where "element" is the element the plugin is attached to; // a public method. for demonstration purposes only - remove it! plugin.foo_public_method = function() { // code goes here } // private methods // these methods can be called only from inside the plugin like: // methodName(arg1, arg2, ... argn) // a private method. for demonstration purposes only - remove it! var foo_private_method = function() { // code goes here } // fire up the plugin! // call the "constructor" method plugin.init(); } // add the plugin to the jQuery.fn object $.fn.pluginName = function(options) { // iterate through the DOM elements we are attaching the plugin to return this.each(function() { // if plugin has not already been attached to the element if (undefined == $(this).data('pluginName')) { // create a new instance of the plugin // pass the DOM element and the user-provided options as arguments var plugin = new $.pluginName(this, options); // in the jQuery version of the element // store a reference to the plugin object // you can later access the plugin and its methods and properties like // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or // element.data('pluginName').settings.propertyName $(this).data('pluginName', plugin); } }); } })(jQuery);
九,性能优化
1,避免不必要的 DOM 操作
浏览器遍历 DOM 元素的代价是昂贵的。最简单优化 DOM 树查询的方案是,当一个元素出现多次时,将它保存在一个变量中,就避免多次查询 DOM 树了。
// Recommended var myList = ""; var myListHTML = document.getElementById("myList").innerHTML; for (var i = 0; i < 100; i++) { myList += "<span>" + i + "</span>"; } myListHTML = myList; // Not recommended for (var i = 0; i < 100; i++) { document.getElementById("myList").innerHTML += "<span>" + i + "</span>"; }
2,缓存数组的长度
循环无疑是和 JavaScript 性能非常相关的一部分。通过存储数组的长度,可以有效避免每次循环重新计算。
注: 虽然现代浏览器引擎会自动优化这个过程,但是不要忘记还有旧的浏览器。
var arr = new Array(1000), len, i; // Recommended - size is calculated only 1 time and then stored for (i = 0, len = arr.length; i < len; i++) { } // Not recommended - size needs to be recalculated 1000 times for (i = 0; i < arr.length; i++) { }
3,异步加载第三方内容
当你无法保证嵌入第三方内容比如 Youtube 视频或者一个 like/tweet 按钮可以正常工作的时候,你需要考虑用异步加载这些代码,避免阻塞整个页面加载。
(function() { var script, scripts = document.getElementsByTagName('script')[0]; function load(url) { script = document.createElement('script'); script.async = true; script.src = url; scripts.parentNode.insertBefore(script, scripts); } load('//apis.google.com/js/plusone.js'); load('//platform.twitter.com/widgets.js'); load('//s.widgetsite.com/widget.js'); }());
4,避免使用jQuery实现动画
- 禁止使用 slideUp/Down() fadeIn/fadeOut() 等方法;
- 尽量不使用 animate() 方法;
移动端优化
移动Web问题小结
http://www.alloyteam.com/2015/06/yi-dong-web-wen-ti-xiao-jie/
移动端统计
https://github.com/jtyjty99999/mobileTech
关于无线端Web解决方案
http://am-team.github.io/about/about.html
click 的300ms延迟响应
click 事件因为要等待双击确认,会有 300ms 的延迟,体验并不是很好。
开发者大多数会使用封装的 tap 事件来代替click 事件,所谓的 tap 事件由 touchstart 事件 + touchmove 判断 + touchend 事件封装组成。