1 前言
HTML 作為描述網頁結構的超文本標記語言,一直有著廣泛的應用。本文檔的目標是使 HTML 代碼風格保持一致,容易被理解和被維護。
2 代碼風格
2.1 縮進與換行
[強制] 使用 4
個空格做為一個縮進層級,不允許使用 2
個空格 或 tab
字符。
解釋:
對于非 HTML 標簽之間的縮進,比如 script 或 style 標簽內容縮進,與 script 或 style 標簽的縮進同級。
示例:
<style>
/* 樣式內容的第一級縮進與所屬的 style 標簽對齊 */
ul {
padding: 0;
}
</style>
<ul>
<li>first</li>
<li>second</li>
</ul>
<script>
// 腳本代碼的第一級縮進與所屬的 script 標簽對齊
require(['app'], function (app) {
app.init();
});
</script>
[建議] 每行不得超過 120
個字符。
2.2 命名
[強制] class
必須單詞全字母小寫,單詞間以 -
分隔。
[強制] class
必須代表相應模塊或部件的內容或功能,不得以樣式信息進行命名。
示例:
<!-- good -->
<div class="sidebar"></div>
<!-- bad -->
<div class="left"></div>
[強制] 元素 id
必須保證頁面唯一。
解釋:
同一個頁面中,不同的元素包含相同的 id
,不符合 id
的屬性含義。并且使用 document.getElementById
時可能導致難以追查的問題。
[建議] id
建議單詞全字母小寫,單詞間以 -
分隔。同項目必須保持風格一致。
[建議] id
、class
命名,在避免沖突并描述清楚的前提下盡可能短。
示例:
<!-- good -->
<div id="nav"></div>
<!-- bad -->
<div id="navigation"></div>
<!-- good -->
<p class="comment"></p>
<!-- bad -->
<p class="com"></p>
<!-- good -->
<span class="author"></span>
<!-- bad -->
<span class="red"></span>
[強制] 禁止為了 hook 腳本
,創建無樣式信息的 class
。
解釋:
不允許 class
只用于讓 JavaScript 選擇某些元素,class
應該具有明確的語義和樣式。否則容易導致 CSS class 泛濫。
使用 id
、屬性選擇作為 hook 是更好的方式。
[強制] 同一頁面,應避免使用相同的 name
與 id
。
解釋:
IE 瀏覽器會混淆元素的 id
和 name
屬性, document.getElementById
可能獲得不期望的元素。所以在對元素的 id
與 name
屬性的命名需要非常小心。
2.3 標簽
[強制] 標簽名必須使用小寫字母。
[強制] 對于無需自閉合的標簽,不允許自閉合。
解釋:
常見無需自閉合標簽有 input
、br
、img
、hr
等。
[強制] 對 HTML5
中規定允許省略的閉合標簽,不允許省略閉合標簽。
[強制] 標簽使用必須符合標簽嵌套規則。
解釋:
比如 div
不得置于 p
中,tbody
必須置于 table
中。
[建議] HTML 標簽的使用應該遵循標簽的語義。
解釋:
下面是常見標簽語義
- p - 段落
- h1,h2,h3,h4,h5,h6 - 層級標題
- strong,em - 強調
- ins - 插入
- del - 刪除
- abbr - 縮寫
- code - 代碼標識
- cite - 引述來源作品的標題
- q - 引用
- blockquote - 一段或長篇引用
- ul - 無序列表
- ol - 有序列表
- dl,dt,dd - 定義列表
[建議] 在 CSS 可以實現相同需求的情況下不得使用表格進行布局。
解釋:
在兼容性允許的情況下應盡量保持語義正確性。對網格對齊和拉伸性有嚴格要求的場景允許例外,如多列復雜表單。
[建議] 標簽的使用應盡量簡潔,減少不必要的標簽。
2.4 屬性
[強制] 屬性名必須使用小寫字母。
[強制] 屬性值必須用雙引號包圍。
解釋:
不允許使用單引號,不允許不使用引號。
[建議] 布爾類型的屬性,建議不添加屬性值。
示例:
<input type="text" disabled>
<input type="checkbox" value="1" checked>
[建議] 自定義屬性建議以 xxx-
為前綴,推薦使用 data-
。
解釋:使用前綴有助于區分自定義屬性和標準定義的屬性。
3 通用
3.1 DOCTYPE
[強制] 使用 HTML5
的 doctype
來啟用標準模式,建議使用大寫的 DOCTYPE
。
[建議] 啟用 IE Edge 模式。
示例:
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
[建議] 在 html
標簽上設置正確的 lang
屬性。
解釋:
有助于提高頁面的可訪問性,如:讓語音合成工具確定其所應該采用的發音,令翻譯工具確定其翻譯語言等。
示例:<html lang="zh-CN">
3.2 編碼
[強制] 頁面必須使用精簡形式,明確指定字符編碼。指定字符編碼的 meta
必須是 head
的第一個直接子元素。
解釋:見 HTML5 Charset能用嗎 一文。
示例:
<html>
<head>
<meta charset="UTF-8">
......
</head>
<body>
......
</body>
</html>
[建議] HTML
文件使用無 BOM
的 UTF-8
編碼。
解釋:UTF-8編碼具有更廣泛的適應性。
BOM` 在使用程序或工具處理文件時可能造成不必要的干擾。
3.3 CSS 和 JavaScript 引入
[強制] 引入 CSS
時必須指明 rel="stylesheet"
。
[建議] 引入 CSS
和 JavaScript
時無須指明 type
屬性。
解釋:text/css
和 text/javascript
是 type
的默認值。
[建議] 展現定義放置于外部 CSS
中,行為定義放置于外部 JavaScript
中。
解釋:結構-樣式-行為的代碼分離,對于提高代碼的可閱讀性和維護性都有好處。
[建議] 在 head
中引入頁面需要的所有 CSS
資源。
解釋:在頁面渲染的過程中,新的CSS可能導致元素的樣式重新計算和繪制,頁面閃爍。
[建議] JavaScript
應當放在頁面末尾,或采用異步加載。
解釋:將 script
放在頁面中間將阻斷頁面的渲染。
4 head
4.1 title
[強制] 頁面必須包含 title
標簽聲明標題。
[強制] title
必須作為 head
的直接子元素,并緊隨 charset
聲明之后。
解釋:title
中如果包含 ASCII 之外的字符,瀏覽器需要知道字符編碼類型才能進行解碼,否則可能導致亂碼。
4.2 favicon
[強制] 保證 favicon
可訪問。
解釋:在未指定 favicon 時,大多數瀏覽器會請求 Web Server 根目錄下的 favicon.ico
。為了保證 favicon 可訪問,避免 404,必須遵循以下兩種方法之一:
- 在 Web Server 根目錄放置
favicon.ico
文件。 - 使用
link
指定 favicon。
示例:
<link rel="shortcut icon" href="path/to/favicon.ico">
4.3 viewport
[建議] 若頁面欲對移動設備友好,需指定頁面的 viewport
。
解釋:viewport meta tag 可以設置可視區域的寬度和初始縮放大小,避免在移動設備上出現頁面展示不正常。
比如,在頁面寬度小于 980px
時,若需 iOS 設備友好,應當設置 viewport 的 width
值來適應你的頁面寬度。同時因為不同移動設備分辨率不同,在設置時,應當使用 device-width
和 device-height
變量。
另外,為了使 viewport 正常工作,在頁面內容樣式布局設計上也要做相應調整,如避免絕對定位等。
5 圖片
[強制] 禁止 img
的 src
取值為空。延遲加載的圖片也要增加默認的 src
。
解釋:src
取值為空,會導致部分瀏覽器重新加載一次當前頁面,參考:https://developer.yahoo.com/performance/rules.html#emptysrc
[建議] 避免為 img
添加不必要的 title
屬性。
解釋:多余的 title
影響看圖體驗,并且增加了頁面尺寸。
[建議] 為重要圖片添加 alt
屬性。
解釋:可以提高圖片加載失敗時的用戶體驗。
[建議] 添加 width
和 height
屬性,以避免頁面抖動。
[建議] 有下載需求的圖片采用 img
標簽實現,無下載需求的圖片采用 CSS 背景圖實現。
解釋:
- 產品 logo、用戶頭像、用戶產生的圖片等有潛在下載需求的圖片,以
img
形式實現,· - 無下載需求的圖片,比如:icon、背景、代碼使用的圖片等,盡可能采用 CSS 背景圖實現。
6 表單
6.1 控件標題
[強制] 有文本標題的控件必須使用 label
標簽將其與其標題相關聯。
有兩種方式:
- 將控件置于
label
內。 -
label
的for
屬性指向控件的id
。
推薦使用第一種,減少不必要的 id
。如果 DOM 結構不允許直接嵌套,則應使用第二種。
6.2 按鈕
[強制] 使用 button
元素時必須指明 type
屬性值。
解釋:button
元素的默認 type
為 submit
,如果被置于 form
元素中,點擊后將導致表單提交。為顯示區分其作用方便理解,必須給出 type
屬性。
[建議] 盡量不要使用按鈕類元素的 name
屬性。
解釋:由于瀏覽器兼容性問題,使用按鈕的 name
屬性會帶來許多難以發現的問題。具體情況可參考此文。
7 模板中的 HTML
[建議] 模板代碼的縮進優先保證 HTML 代碼的縮進規則。
示例:
<!-- good -->
{if $display == true}
<div>
<ul>
{foreach $item_list as $item}
<li>{$item.name}<li>
{/foreach}
</ul>
</div>
{/if}
<!-- bad -->
{if $display == true}
<div>
<ul>
{foreach $item_list as $item}
<li>{$item.name}<li>
{/foreach}
</ul>
</div>
{/if}
[建議] 模板代碼應以保證 HTML 單個標簽語法的正確性為基本原則。
示例:
<!-- good -->
<li class="{if $item.type_id == $current_type}focus{/if}">{ $item.type_name }</li>
<!-- bad -->
<li {if $item.type_id == $current_type} class="focus"{/if}>{ $item.type_name }</li>
[建議] 在循環處理模板數據構造表格時,若要求每行輸出固定的個數,建議先將數據分組,之后再循環輸出。
示例:
<!-- good -->
<table>
{foreach $item_list as $item_group}
<tr>
{foreach $item_group as $item}
<td>{ $item.name }</td>
{/foreach}
<tr>
{/foreach}
</table>
<!-- bad -->
<table>
<tr>
{foreach $item_list as $item}
<td>{ $item.name }</td>
{if $item@iteration is div by 5}
</tr>
<tr>
{/if}
{/foreach}
</tr>
</table>
8 CSS命名及書寫規范
CSS書寫順序
1.位置屬性(position, top, right, z-index, display, float等)
2.大小(width, height, padding, margin)
3.文字系列(font, line-height, letter-spacing, color- text-align等)
4.背景(background, border等)
5.其他(animation, transition等)
CSS縮寫屬性
去掉小數點前的“0”
16進制顏色代碼縮寫
簡寫類名,但前提是要讓人看懂你的命名才能簡寫
連字符CSS選擇器命名規范
1.長名稱或詞組可以使用中橫線來為選擇器命名。
2.不建議使用“_”下劃線來命名CSS選擇器,為什么呢?
輸入的時候少按一個shift鍵;
瀏覽器兼容問題 (比如使用_tips的選擇器命名,在IE6是無效的);
能良好區分JavaScript變量命名JS變量命名是用“_”
不要隨意使用Id
id在JS是唯一的,不能多次使用,而使用class類選擇器卻可以重復使用,另外id的優先級優先與class,所以id應該按需使用
為選擇器添加狀態前綴
有時候可以給選擇器添加一個表示狀態的前綴,讓語義更明了,比如下圖是添加了“.is-”前綴
減少選擇器層級,選擇器的嵌套最好不要超過三層,合理使用命名空間,避免命名沖突
.header .logo .text{} 可以優化成 .haeder .logo-text{}
盡量不使用 !important 聲明
當需要強制指定樣式且不允許任何場景覆蓋時,通過標簽內聯和 !important 定義樣式。
利用CSS繼承減少代碼量
常見的可以繼承的屬性比如: color,font-size,font-family等等
不可繼承的比如: position,display,float等
不濫用浮動
雖然浮動不可避免,但不可否認很多css bug是由于浮動而引起。CSS Lint一旦檢測出樣式文件中有超過10次的浮動便會提示警告。
js前端編碼規范
這是一份旨在增強團隊的開發協作,提高代碼質量和打造開發基石的編碼風格規范,其中包含了 HTML, JavaScript 和 CSS/SCSS 這幾個部分。我們知道,當一個團隊開始指定并實行編碼規范的話,錯誤就會變得更加顯而易見。如果一段特定的代碼不符合規范的話,它有可能只是代碼風格錯誤,而也有可能會是 bug。早期指定規范就使得代碼審核得以更好的開展,并且可以更精確的地定位到錯誤。只要開發者們能夠保證源代碼源文件都嚴格遵循規范,那接下去所使用的混淆、壓縮和編譯工具則可投其所好不盡相同。
一、JavaScript 相關規范
命名
(1) 變量, 使用 Camel 命名法(駝峰命名法)。
// 推薦的命名
var isHotel,
isHotelBeijing,
// 不推薦的命名
var is_Hotel,
ishotelbeijing,
(2) 私有屬性、變量和方法以下劃線 _ 開頭。
var privateProperty
(3) 常量, 使用全部字母大寫,單詞間下劃線()分隔的命名方式,通常用于ajax請求url,和一些不會改變的數據
var PLACE_TYPE = 'hotel';
(4) 函數,使用 Camel 命名法, 函數的參數, 使用 Camel 命名法。
(5) 類,使用 Pascal 命名法,即采用駱駝峰的命名且首字母大寫; 類的 方法 / 屬性, 使用 Camel 命名法
如:
function TextNode(value, engine) {
this.value = value;
this.engine = engine;
}
命名語法
(1) 類名,使用名詞。
function Engine(options) {}
(2) 函數名,使用動賓短語。
function getStyle(element) {}
(3) boolean 類型的變量使用 is 或 has 開頭。
var isReady = false;
var hasMoreCommands = false;
(4) Promise 對象用動賓短語的進行時表達。
var loadingData = ajax.get('url');
loadingData.then(callback);
注釋
原則:
a) As short as possible(如無必要,勿增注釋):盡量提高代碼本身的清晰性、可讀性。
b) As long as necessary(如有必要,盡量詳盡):合理的注釋、空行排版等,可以讓代碼更易閱讀、更具美感。
(1) 單行注釋:必須獨占一行。// 后跟一個空格,縮進與下一行被注釋說明的代碼一致。
(2) 多行注釋:避免使用 /.../ 這樣的多行注釋。有多行注釋內容時,使用多個單行注釋。
(3) 函數/方法注釋
函數/方法注釋必須包含函數說明,有參數和返回值時必須使用注釋標識。;
參數和返回值注釋必須包含類型信息和說明;
當函數是內部函數,外部不可訪問時,可以使用 @inner 標識;
1. /**
2. * 函數描述
3. *
4. * @param {string} p1 參數1的說明
5. * @param {string} p2 參數2的說明,比較長
6. * 那就換行了.
7. * @param {number=} p3 參數3的說明(可選)
8. * @return {Object} 返回值描述
9. */
10. function foo(p1, p2, p3) {
11. var p3 = p3 || 10;
12. return {
13. p1: p1,
14. p2: p2,
15. p3: p3
16. };
17. }
(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.
*/
變量聲明:
總是使用 var(如果用ES6 則let ) 來聲明變量。如不指定 var,變量將被隱式地聲明為全局變量,這將對變量難以控制
在同一個函數內部,局部變量的聲明必須置于頂端。塊內函數必須用局部變量聲明,切勿在循環中創建函數
// 錯誤的寫法
var call = function(name) {
if (name == "hotel") {
function foo() {
console.log("hotel foo");
}
}
foo && foo();
}
// 推薦的寫法
var call = function(name) {
var foo;
if (name == "hotel") {
foo = function() {
console.log("hotel foo");
}
}
foo && foo();
}
建議與禁止
(1) 分號
總是使用分號,因為隱式的代碼嵌套會引發難以察覺的問題。當然我們更要從根本上來杜絕這些問題 ,給自己的表達式加上分號吧
(2) (禁止)使用eval
eval() 不但混淆語境還很危險,總會有比這更好、更清晰、更安全的另一種方案來寫你的代碼,因此盡量不要使用 evil 函數;eg:采取$.parseJSON
(3) 除了三目運算,if,else等(禁止)簡寫
(4) (推薦)使用局部變量緩存反復查找的對象(包括但不限于全局變量、dom查詢結果、作用域鏈較深的對象)
// 緩存對象
var getComment = function() {
var dom = $("#common-container"), // 緩存dom
appendTo = $.appendTo, // 緩存全局變量
data = this.json.data; // 緩存作用域鏈較深的對象
}
(5) 當需要緩存this時必須推薦使用self變量進行緩存
// 緩存this
function Row(name) {
var self = this;
self.name = name;
$(".row").click(function() {
self.getName();
});
}
self是一個保留字,不過用它也沒關系。在這里,看個人愛好吧,可以用_this, that, me等這些詞,都行,但是團隊開發的時候統一下比較好,建議大家用self;
(6) (不推薦)超長函數, 當函數超過100行,就要想想是否能將函數拆為兩個或多個函數
(7) 不要在 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.
//推薦
function printArray(arr) {
var l = arr.length;
for (var i = 0; i < l; i++) {
print(arr[i]);
}
}
(8) 操作符始終寫在前一行, 以免分號的隱式插入產生預想不到的問題。
var x = a ? b : c;
var y = a ?
longButSimpleOperandB : longButSimpleOperandC;
var z = a ?
moreComplicatedB :
moreComplicatedC;
. 操作符也是如此:
var x = foo.bar().
doSomething().
doSomethingElse();
(9) 條件(三元)操作符 (?:)
三元操作符用于替代 if 條件判斷語句。
// Not recommended
if (val != 0) {
return foo();
} else {
return bar();
}
// Recommended
return val ? foo() : bar();
(10) && 和 ||
二元布爾操作符是可短路的, 只有在必要時才會計算到最后一項。
// 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);
}
(11) 修改內建對象的原型鏈
修改內建的諸如 Object.prototype 和 Array.prototype 是被嚴厲禁止的。修改其它的內建對象比如 Function.prototype,雖危害沒那么大,但始終還是會導致在開發過程中難以 debug 的問題,應當也要避免。
(12) 圓括號
一般在語法和語義上真正需要時才謹慎地使用圓括號。不要用在一元操作符上,例如 delete, typeof 和 void,或在關鍵字之后,例如 return, throw, case, new 等。
(13) 字符串
統一使用單引號(‘),不使用雙引號(“)。這在創建 HTML 字符串非常有好處:
var msg = 'This is some HTML <div class="makes-sense"></div>';
(14) 自定義 toString() 方法
你可以通過自定義 toString() 來控制對象字符串化。這很好,但你必須保證你的方法總是成功并不會有其它副作用。如果你的方法達不到這樣的標準,那將會引發嚴重的問題。如果 toString() 調用了一個方法,這個方法做了一個斷言[3] ,當斷言失敗,它可能會輸出它所在對象的名稱,當然對象也需要調用 toString()
(15) 異常
基本上你無法避免出現異常,特別是在做大型開發時(使用應用開發框架等等)。在沒有自定義異常的情況下,從有返回值的函數中返回錯誤信息一定非常的棘手,更別提多不優雅了。不好的解決方案包括了傳第一個引用類型來接納錯誤信息,或總是返回一個對象列表,其中包含著可能的錯誤對象。以上方式基本上是比較簡陋的異常處理方式。適時可做自定義異常處理。在復雜的環境中,你可以考慮拋出對象而不僅僅是字符串(默認的拋出值)。
if(name === undefined) {
throw {
name: 'System Error',
message: 'A name should always be specified!'
}
}