正因為我們是前端,所以代碼更需要優雅
前端是個很特殊,帶點矛盾的職位。所以我們的“前端攻城師”也大都是些矛盾體。矛盾在感性和理性之間,矛盾在文藝和三俗之間,矛盾在放任和嚴謹之間。作為所謂的“攻城師”,攻的不僅是“前端”這座善變詭異的高城,同時也是在攻我們自己對于藝術和編碼的心防。
【關于HTML】
語義化
語義化,是什么?即用正確的標簽做正確的事。我一直認為學一種編程語言和學一門我們常規意義里的“語言”如漢語,英語,其實是類似的。單字和單詞以及語法都是一門語言的組成部分,但卻不是最重要的部分。怎么去組織這些單字和語法去表達正確的意思才是語言的精髓。這就好比漢語我們每個人都會寫,但是能用漢語寫出驚艷的散文,寫出邏輯嚴謹的小說的又有多少呢?所以,我們普通人和一些優秀的作家的最大的區別或許不在于知道單詞的多少,了解語法的多少,而在于敘述一件事情,表達一個觀點時的思維。
好像扯遠了。回到html的語義化上。我說了,重點不在于你知曉標簽的多少。哪怕你知曉了所有標簽,甚至能區分了不同的DTD下符合規范的標簽。那又怎么樣呢?僅僅等同于熟背了一本《現代漢語詞典》。每個標簽都有他自己的語義。這也是為什么我們會拋棄用table來布局的方式。因為table本來的語義很明晰,就是“數據表格”,他該為數據表格而生,而不是為布局而生。
舉一個一線互聯網公司一個關于合理使用html標簽的筆試題:
請把一段簡單的html寫成你覺得規范的,優雅的html。
如果我們考慮到標簽的閉合,考慮到標簽的大小寫。于是我們會這樣改:
如果我們考慮到合理使用標簽。為什么要兩個br連用?其實那里應該已經可以分為兩個段落了。所以:
如果上面一段html出現在一個內容充實的頁面里,其實基本也可以了,可是,如果我們假設我們一個頁面的主要內容就是上面那一小段html,或者甚至一個頁面就那一小段。那么,或許我們還需要更好的語義去修飾:
到此為止,在某些情況下上面的強語義的方式是合理的,而或許某些情況上面的代碼片段是有些冗余的。正如我們用漢語寫文章,修飾的形容詞用少了會覺得無味,用多了會顯得口味重。所以,合理的判別文檔在頁面的權重以及用合理的標簽去修飾它顯得尤為重要。
清晰地結構,與表現分離
說到html結構,我不得不說一種經典的思想:面向對象。OO的思想自從在經典的C語言中被推廣開來后,一直長興不衰,面向對象的確是編碼中目前為此最為優雅的方式。有人或許會說,你說c,c++,java等面向對象的編碼,我能理解,你說JavaScript也能面向對象的編碼,我也能接受,至于html和css也能面向對象?這就有點唐突了。是的,html和css一個作為“置標語言”,一個作為樣式表。能否真正的呈現面向對象的思想有待考究。不過這并不妨礙我們把OO的思想貫穿于我們的編碼中。
我們知道。html是以“盒模型”為基礎的,那我們不妨就面向“盒子”這個對象來架構我們的html。比如一個典型的“盒模型”類似:
<h2 class="box-title"></h2>
<div class="box-con"></div>
<div class="box-footer"></div>
</div>
如果我們把這樣一個盒子作為我們的“基對象”的話,那么html的結構會類似于下面這樣:
<!-- 文檔包裹 -->
<div class="wp">
<!-- header -->
<div id="header" class="header">
<div class="box">
<h2 class="box-title"></h2>
<div class="box-con"></div>
<div class="box-footer"></div>
</div>
</div>
<!-- main content -->
<div id="content" class="content">
<div class="box">
<h2 class="box-title"></h2>
<div class="box-con">
<!-- left column -->
<div class="box col-left">
...
</div>
<!-- right column -->
<div class="box col-right">
...
</div>
</div>
<div class="box-footer"></div>
</div>
</div>
<!-- footer -->
<div id="footer" class="footer">
<div class="box">
<h2 class="box-title"></h2>
<div class="box-con"></div>
<div class="box-footer"></div>
</div>
</div>
</div>
</body>
這只是一個基本的例子,有些box可能沒有title,有些可能不需要footer,根據實際情況隨機而變即可。
至于結構與表現的分離,應該還是和一些小規范更有關系,如:
不要使用內聯樣式
不要使用帶表現層的標簽,如<font>,<big>,<i>,<center>...等等
【關于css】
樣式的分離和聚合 世界上所有的事物都遵循的“物極必反”的道理,而這個道理在css的編碼里顯得尤為明顯。這時候“中庸”就顯得尤為重要了。 我們需要高效的,少冗余的css,所以會提倡css的分離,亦即OO-css。可是如果css分離的太徹底了,在html的維護上會是很大的問題,等于是犧牲了html的可維護性與部分優雅來成全一種偏激和絕對的oo-css。這顯然也是不合理的。 我們在html文檔里定義css樣式渲染類名用的是class這個屬性。提到class,在編碼語言里是一個默認的“類”的代名詞。也就是說,其實css的作者其實在創作css的時候其實就是基于“類”來考慮的,要不然也不會用class這個詞作為css樣式的屬性名。 這自然不奇怪,oo-css的思想很早就有人提出來了,可是世上總有些矛盾是難以調和的,考慮下面的css:
padding: 8px 10px;
background: red;
border: 1px solid #CCC;
color: blue;
}
<p class="con-text">test</p>
我們需要多個這樣類似的p,但又要求文本顏色不一樣的話,會怎么辦,重寫多個類? .con-text1, .con-text2 ... ?
顯然太不現實,也太過冗余,所以或許我們需要用的面向對象中一個重要的思路--抽像公共接口。或許我們可以這么做:
padding: 8px 10px;
background: red;
border: 1px solid #ccc;
}
.red {color: red}
.blue {color: blue}
...
<p class="normal-text red">test1</p>
<p class="normal-text blue">test2</p>
是的,這樣做沒錯,而且很好,可是慢著,如果我們還要要求每個p不僅文本顏色不一樣,背景色也不一樣。。。怎么辦?有人會想,我們照上面的思路繼續抽象就好了。比如:
padding: 8px 10px;
border: 1px solid #ccc;
}
.bg-red {background: red}
.blue {color: blue}
<p class="normal-text bg-red blue">test</p>
我們繼續糾結下去,我們要border也不同,甚至padding也不同,怎么辦?還繼續分離嗎?如果我們鉆個牛角尖,我們對css進行徹底的分離,最終的結果會全是類似于:
.blue {color: blue}
.pad-t8 {padding-top: 8px}
.pad-l10 {padding-left: 10px}
...
最終的結果就不是面向對象了,而是面向屬性了...是的,分離的越徹底,開發時的效率會越高,css文件也會越小越精簡。可是別忘了這樣做的后果是可能一個元素需要寫5個,甚至10個并列的css類名去渲染...
那這樣,我們所謂的“類”意義何在,這樣又和寫style內聯樣式有什么分別?我們維護時是不是要在html文檔里滿篇去找要幾十上百個類名去增刪改??
所以css分離是好的,可是過度的分離是不行的。如何把握尺度和權重才是最重要的。鄙人有幾個小建議。
1.css面向對象請面向通用的對象。比如box,一個網站可以有多個box樣式,boxA,boxB...boxF...等等,對應響應的boxA-tit,boxB-tit...等等,為這些通用的對象抽離公用的樣式
2.可以為全站都通用的樣式進行抽離:比如清除浮動
content: ".";
display: bloc;
height: 0;
clear: both;
visibility: hidden;
}
/* Hides from IE-mac \*/
.clearfix {zoom: 1;}
/* End hide from IE-mac */
3.可以為柵格化的布局樣式做抽離, 如:col-a{width:..}, clo-b {width: ..}等等
4.需要的時候局部的面向屬性的絕對分離也是可以的,但請在有需要的時候局部使用。
5.建議class的并列類名不要大于3個,否則就需要考慮是否應該稍微聚合一下了。
以上只是個人建議,每個人在項目或建站時遇到的需求可能都不一樣,自己秉著“中庸”的心態去權衡css的分離與聚合很重要。
【關于JavaScript】
優雅的js
關于這個方面,大家討論的就比較多了。我這里只舉很簡單的例子,比如我們要寫一個幻燈片。思路我們有了,先初始化,然后需要一個變換函數,可能我們還需要一些漸變的效果,所以還需要一個漸變的函數,最后我們還需要自動輪播。有了思路,我們的代碼可能大概會這樣:
...
pos();
}
function pos () { // 每張圖片輪換函數
...
window.timer = setInterval(function(){anim()}, 20);
}
function anim () { // 漸變的函數
...
if(finish) { //變換結束
clearInter(timer);
auto();
}
}
function auto () {
setInterval(function(){pos()}, 4000);
}
/* init */
init();
這樣的方式我們大概可以理解為一種過程式編碼。當然這樣的風險有很多,比如,變量名污染,模塊化管理,多實例重用等等都是問題。所以它顯然不夠優雅。我自己常用的方式:
var init = function () {
...
this.pos();
}
init.protorype = {
pos : function () {
//TODO
},
anim : function () {
//TODO
}
auto : function () {
//TODO
}
}
return init;
}();
/* init */
new slider();
至于為什么會推薦這種構造函數/原型 的混合方式來構建,可以參考之前的“我所了解的類構造方式”以及“動態原型”擴展的文章。另外還有種抽象構造類的方式也是我挺喜歡的:
create: function () {
return function () {
return this.init.apply(this, arguments);
}
}
};
var slider = Class.create();
slider.prototype = {
init: function () {
//TODO
}
}
/* init */
new slider();
好了,文已至此,也差不多了,前端作為UED里的一個職位,干的卻是編碼的工作,注定了它的特殊性,所以我們不得不說,正因為我們是前端,所以我們更需要“優雅”!!
ps:以上全是個人觀點,不一定適用于各位同仁,請謹慎取舍...