模塊化是現(xiàn)今我們隨處都可以聽到的一個(gè)名詞,什么是模塊化?為什么我們需要模塊化?這是本系列文章我們要弄明白的一個(gè)問題。我們也借這部分內(nèi)容,順帶回顧一下前端的發(fā)展歷程。
說實(shí)話,模塊化這個(gè)主題有點(diǎn)大,我一時(shí)也不知道從哪里講起比較合適,通常來說,前端的工作內(nèi)容主要涉及三個(gè)方面:html、css、js(javascript),其他的像as(actionscript,flash的腳本語言)、jsp、smarty等等模版類的語法標(biāo)記我們?cè)诖司拖嚷匀チ?,因?yàn)椴皇翘貏e重要。那我們所說的模塊化也可以分別當(dāng)成這三條線去看,如html的模塊化、css的模塊化,以及js的模塊化,這三者我們稱為(web)前端模塊化,搞清楚這幾者的關(guān)系,我們接下來要了解的事情已經(jīng)很清晰了。
我們單獨(dú)來講,我想先從css,因?yàn)檫@是我認(rèn)為最容易入手且非常鮮明的一塊內(nèi)容。
背景
起初的.css是長什么樣的?
/* index.css */
body {
margin: 0;
padding: 0;
font-size: 18px;
}
.box {
background: #333;
color: #fff;
}
.box .list {
margin-left: 10px;
}
.box .list .item {
border-bottom: 1px solid #ccc;
}
.box .list .item:last-child {
border-bottom: 0;
}
.box .list .item a {
text-decoration: none;
color: #fff;
}
.box .list .item span {
color: red;
}
.box .list .item a ... {
...
}
是不是很熟悉?一個(gè)簡(jiǎn)單的手打的列表模塊。
這里存在的問題是:
- 按照這個(gè)順序?qū)懴氯?,選擇器會(huì)越寫越長,造成書寫累贅;
- 越來越長的選擇器容易使我們混淆dom的空間順序,想象如果有好幾個(gè)平級(jí)的選擇器(如.box .list .item a與.box .list .item span),我們可能一時(shí)看不出這兩者的關(guān)系,是父子還是兄弟元素?
- 維護(hù)困難,假設(shè)我們需要重構(gòu)這個(gè)box,在.box和.list之間加入一層.wrap,在.item與a和span之間加入一層.block,那簡(jiǎn)直就是個(gè)災(zāi)難,我們要謹(jǐn)慎地找到確切的位置,然后再找到所有匹配的、長長的選擇器,在合適的位置全部做修改;
- 我們很難從做到復(fù)用,假設(shè)我們?cè)诹硗庖粋€(gè)頁面也需要這個(gè)box,那我們就需要把所有跟box相關(guān)的部分復(fù)制粘貼一份,而當(dāng)這個(gè)box需要修改的時(shí)候,我們可能要重新找出所有用到這個(gè)box的地方,然后又是復(fù)制粘貼一份——當(dāng)然,有人說這個(gè)問題是可以通過一定的方法解決的,我們后面再來討論這個(gè)問題;
……
(歡迎補(bǔ)充css的開發(fā)痛點(diǎn))
事實(shí)上我們手打css遇到的問題可以大致歸納為以下幾點(diǎn):
- 選擇器繁瑣冗長;
- 命名沖突;
- 層級(jí)結(jié)構(gòu)不清晰;
- 代碼難以復(fù)用;
問題很多,怎么去解決?由于css的發(fā)展很緩慢,在工具上也一直沒有進(jìn)展,導(dǎo)致這些問題,比如上述的第一點(diǎn),幾乎無解。所以問題往往要依賴“規(guī)范”來解決。我們先來看代碼復(fù)用。
復(fù)用
要實(shí)現(xiàn)代碼復(fù)用很簡(jiǎn)單,我們只需要提供一個(gè)公共css庫,來存放我們的公共樣式以及公共模塊即可:
/* common.css */
body {
background: #fff;
color: #333;
font-size: 16px;
}
.box ... {
background: #333;
color: #fff;
...
}
.another-box ... {
...
}
然后我們?cè)谄渌腸ss文件中引用這個(gè)common.css,這樣就實(shí)現(xiàn)了代碼的復(fù)用,只要是想全局共享的樣式和模塊,只要在這里添加進(jìn)去就可以了。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
<link rel="stylesheet" type="text/css" href="./style/common.css">
<link rel="stylesheet" type="text/css" href="./style/index.css">
</head>
<body>
<div class="box">
...
</div>
<div class="another-box">
...
</div>
</body>
</html>
很完美,
——至少目前為止是這樣沒錯(cuò)。
這里我們來探究幾種情況:
- 假設(shè)我們這個(gè)項(xiàng)目非常大,大概有20個(gè)頁面這么多,那么我們每做一個(gè)頁面就會(huì)往common里面補(bǔ)充3~4個(gè)公共樣式/模塊,那么在這個(gè)項(xiàng)目開發(fā)完成以后,common的體積可能要比其他css的體積都大;
- 假設(shè)有幾個(gè)這樣的頁面,他們本身內(nèi)容非常少,比如404頁面,可能只需要用到少量的公共樣式,但是由于考慮到維護(hù)問題,我們還是要引入common(單獨(dú)寫樣式會(huì)使得該頁面在common更新的時(shí)候無法同步得到更新),這就使得一個(gè)頁面變得很“重”;
- 由于common越寫越大,它所占用的命名就越多,那么我們?cè)谝隿ommon的時(shí)候,即使我們頁面還什么都沒有,但已經(jīng)默認(rèn)被占用了很多的命名,使得我們?cè)谀硞€(gè)頁面的可用命名變少,而且是越來越少;
- 我們?cè)赾ommon中書寫公共模塊,在具體頁面的私有css里書寫私有模塊,假設(shè)現(xiàn)在我們需要全局添加一個(gè)公共模塊.nice-box,我們發(fā)現(xiàn),這個(gè)模塊名已經(jīng)在index.css中被占用了,于是我們?cè)囍衙指某?handsome-box,卻又發(fā)現(xiàn)這個(gè)名字在about.css中被占用了,哦買噶的!
……
瞬間整個(gè)人都不好了,內(nèi)心充滿了絕望,心想還是轉(zhuǎn)行吧,垃圾語言毀我一生。
我們分析一下,上面這些情況其實(shí)重點(diǎn)只有兩個(gè):一、冗余;二、污染。冗余是難免的,為了維護(hù)犧牲一部分靈活性也是可以接受的,不過我們需要用一些方式來減少這樣的冗余,避免讓它成為負(fù)擔(dān);而污染,卻是亟待解決的問題,這顆定時(shí)炸彈隨著項(xiàng)目的增大最終會(huì)變成一場(chǎng)無法挽回的災(zāi)難!這時(shí)候就體現(xiàn)出了命名規(guī)范的重要性了。
這就要求我們用一套合理的規(guī)范來約束和組織我們的代碼。
規(guī)范
編程規(guī)范使得我們的項(xiàng)目在一定程度上是可維護(hù)的。比如針對(duì)類名污染制定了命名規(guī)范,針對(duì)選擇器指定了書寫選擇器所要遵循的規(guī)范,等等。這些規(guī)范都在一定程度上約束了css的書寫,使得項(xiàng)目不至于混亂。網(wǎng)易的NEC是其中一種比較完整的解決方案。有興趣的童鞋可以搜索了解,筆者本身受nec影響較大,所以以下內(nèi)容有一定程度的雷同。
現(xiàn)在我們來試著制定一套css編程規(guī)范,來解決以上提到的問題。
我們規(guī)定頁面由且只由幾種基本結(jié)構(gòu)體構(gòu)成:框架、模塊,以及元件。其他零散的元素,除了是作為模塊的輔助類,否則不能獨(dú)立于這三者存在。
框架
框架是指構(gòu)成頁面的基礎(chǔ)結(jié)構(gòu),它是一個(gè)頁面的筋骨。我們假設(shè)有個(gè)頁面index.html,它的整體最外圍表現(xiàn)為一個(gè)class為.g-index的div,然后它由頁頭(.g-hd)、主體(.g-bd)、頁腳(.g-ft)三個(gè)部分組成:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<div class="g-index">
<div class="g-hd"></div>
<div class="g-bd"></div>
<div class="g-ft"></div>
</div>
</body>
</html>
這樣我們就大概能描繪出一個(gè)頁面的基本輪廓了。緊接著我們來給它補(bǔ)充一些模塊。
模塊
模塊是頁面上數(shù)量最多,同時(shí)也是最重要的部分,它是代碼復(fù)用的主體部分,是一個(gè)個(gè)按照功能劃分的區(qū)域,如導(dǎo)航欄、輪播圖、登錄窗口、信息列表等等,模塊之間相互獨(dú)立,分布在頁面上,嵌在框架的各個(gè)位置上,組成一個(gè)豐富多彩的頁面。
還是以index.html為例,我們假設(shè)頁頭有個(gè)導(dǎo)航欄模塊(.m-nav),主體有個(gè)新聞列表模塊(.m-news),頁腳有個(gè)版權(quán)聲明模塊(.m-copy_right):
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<div class="g-index">
<div class="g-hd">
<div class="m-nav">
nav
</div>
</div>
<div class="g-bd">
<div class="m-news">
news
</div>
</div>
<div class="g-ft">
<div class="m-copy_right">
copy_right
</div>
</div>
</div>
</body>
</html>
元件
元件是獨(dú)立的、可重復(fù)使用的,并且在某些情況下可以作為模塊的組成部分的一種細(xì)顆粒。比如一個(gè)按鈕,一個(gè)logo等等。某種意義上說,它其實(shí)可以等同于模塊,因?yàn)樗鼈儍烧叩膮^(qū)別只是規(guī)模不同而已。模塊更強(qiáng)調(diào)一個(gè)功能完整的整體,而元件則更強(qiáng)調(diào)獨(dú)立性。
我們假設(shè)這個(gè)頁面還需要在頁頭放個(gè)logo(.u-logo),在導(dǎo)航欄中放置一個(gè)登錄按鈕(.u-login_btn):
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<div class="g-index">
<div class="g-hd">
<img class="u-logo" alt="logo">
<div class="m-nav">
nav
<a href="/logoin" class="u-login_btn">登錄</a>
</div>
</div>
<div class="g-bd">
<div class="m-news">
news
</div>
</div>
<div class="g-ft">
<div class="m-copy_right">
copy_right
</div>
</div>
</div>
</body>
</html>
三種基本結(jié)構(gòu)體介紹完,我們回來總結(jié)一下。你一定發(fā)現(xiàn)了一個(gè)現(xiàn)象,在搭建框架的時(shí)候,我給框架元素命名用g-開頭,給模塊命名使用m-,給元件命名使用u-。這是命名規(guī)范的一部分,我們使用這三個(gè)前綴給相應(yīng)結(jié)構(gòu)體命名,就是為了更好地標(biāo)志一個(gè)結(jié)構(gòu)體,更好地展示它的功用,這也是我們常說的 語義化 ,同時(shí)也能實(shí)現(xiàn)隔離作用,起到類似命名空間的效果。
- 框架的命名以
g-開頭,一般與頁面同名,比如index.html,那框架就是最外層就是.g-index,about.html就是.g-about,以此類推,其他常用的內(nèi)部結(jié)構(gòu)有.g-hd(header)、.g-bd(body)、.g-ft(footer)、.g-sd(side)、.g-mn(main)等等; - 模塊命名以
m-開頭,一般以相對(duì)應(yīng)的用途來命名,比如導(dǎo)航欄m-nav、新聞m-news、版權(quán)m-copy_right等等,一般來說模塊名是唯一的,而且模塊本身應(yīng)該是可移植、可復(fù)用的; - 元件命名以
u-開頭,一般以自身含義來命名,比如u-logo表示一個(gè)logo,u-btn表示一個(gè)按鈕。
那么除卻框架、模塊、元件的相關(guān)命名內(nèi)容之外,命名規(guī)范還有以下幾點(diǎn)內(nèi)容:
- 命名盡量以縮寫的方式,言簡(jiǎn)意賅地表達(dá),比如用
bd表達(dá)body,用nav表達(dá)navigator等,使用長長的單詞顯得多余又臃腫; - 前綴與名稱之間用
-連接,而名稱之間的若干單詞以_連接,組合單詞除外,如side-menu; -
z-開頭表示狀態(tài),如z-active、z-succ、z-disabled等等; - 可以根據(jù)需要定制其他開頭,但是請(qǐng)盡量將分類控制在少數(shù),因?yàn)樘嗟姆诸惙炊斐衫Щ蠛筒槐匾姆诸愰_銷,其實(shí)gmuz就已經(jīng)可以滿足日常開發(fā)了。
重構(gòu)common
有了命名規(guī)范,我們可以對(duì)common進(jìn)行一次改寫:
/* common.css */
body {
background: #fff;
color: #333;
font-size: 16px;
}
.m-nav { ... }
.m-news { ... }
.m-copy_right { ... }
ok,現(xiàn)在我們一定程度上緩解了“污染”的問題,至少按照命名規(guī)范,我們的common構(gòu)成由原來籠統(tǒng)的一類,變成了現(xiàn)在gmuz四類,變得更加可管理且“沒那么容易沖突”了,但是這還遠(yuǎn)沒有解決“污染”。
以下為了方便表述,我們把common.css稱為“common”,把對(duì)應(yīng)頁面的css,比如index.html -> index.css、about.html -> about.css,稱為“頁面css”。
這里有個(gè)問題需要細(xì)致思考一下:模塊的屬性。理論上講,一個(gè)模塊應(yīng)該是公有或者私有的,假設(shè)一個(gè)模塊它基本只可能在某個(gè)頁面用,或者我們不打算在其他頁面用到它,我們可以說這個(gè)模塊是這個(gè)頁面的私有模塊,比如文章頁里的文章列表模塊(m-article_list),以及組成這個(gè)模塊的列表單元元件(u-article_item),我們基本可以確定這兩者不會(huì)在其他頁面被復(fù)用到了,那么它們其實(shí)是已經(jīng)默認(rèn)私有的屬性,沒必要放在common里,直接放在article.css就可以了。這樣也可以人為地減少common的體積。那么問題來了,如果模塊既可以存放在common,又可以存放在頁面css,那么我們后續(xù)在common中添加公共模塊的時(shí)候,如何避免模塊名已經(jīng)在頁面css中被占用的情況?(即上文對(duì)common的設(shè)計(jì)提問的第4點(diǎn))
我曾經(jīng)跟一位同事針對(duì)“后續(xù)添加公共模塊可能與其他頁面的私有模塊命名沖突”的問題進(jìn)行探討,最后我們得出兩種解決方案:
- 默認(rèn)由common管理所有模塊,所有模塊默認(rèn)為公共模塊,不允許私有模塊;
- 為公共模塊單獨(dú)使用一種前綴
cm-來做區(qū)分,所有m-前綴的模塊都是私有模塊。
第一種方案會(huì)使得common體積非常大,而且會(huì)一直增大,不可取;第二種方案顯式地聲明模塊屬性,以此來避免沖突,可取。
于是乎又變成了:
/* common.css */
body {
background: #fff;
color: #333;
font-size: 16px;
}
.cm-nav { ... }
.cm-news { ... }
.cm-copy_right { ... }
而我們的私有模塊是這樣的:
/* index.css */
.g-index {
background: #fff;
color: #333;
font-size: 16px;
}
.m-nav { ... }
.m-news { ... }
.m-copy_right { ... }
這樣子處理之后,我們的公共模塊和私有模塊之間的命名沖突就解決了,而且也不會(huì)出現(xiàn)“一個(gè)還什么都沒有頁面引用了common之后,許多的類名就被占用了”的情況,因?yàn)閏ommon絕大部分內(nèi)容都是cm模塊,而頁面自己的css里只能擁有私有的m模塊。
顯然這種方案是可行的,但是我們會(huì)多一種前綴,而且還略丑。但就當(dāng)時(shí)的手打css技術(shù)來說,我們沒有其他更好的解決方案,這個(gè)問題就到這里暫算了結(jié)。我們解決了問題,但是方法還不夠好,后續(xù)等我們提及css預(yù)處理語言的時(shí)候,我們會(huì)提出一些更好的解決方案。
好,接下來我們思考這樣一個(gè)問題:假設(shè)我們已經(jīng)寫完了index頁面,接著寫about頁面,這時(shí)候我們發(fā)現(xiàn),原本在index中的一個(gè)模塊m-news,我們將它歸為私有模塊,而現(xiàn)在在about中居然也需要用到這一個(gè)模塊,于是乎,我們重新回到index頁面,把m-news模塊從index.css轉(zhuǎn)移到了common.css當(dāng)中,并改名為cm-news,然后回到index頁面,把與m-news相關(guān)的內(nèi)容(html、js)都修改成cm-news。這還是在我們能夠意識(shí)到的情況下做的,如果頁面多了起來,我們根本沒有印象哪個(gè)頁面是不是也有這樣一個(gè)模塊,要不要把它提升為公共模塊。一個(gè)月之后,這個(gè)項(xiàng)目一個(gè)星期前已經(jīng)搞定了,現(xiàn)在需要進(jìn)行后續(xù)的開發(fā),加多一個(gè)contact頁面,然后我們又發(fā)現(xiàn),這頁面里用到了一個(gè)原本我們?cè)赼bout頁面里把它劃為私有模塊的m-loc,于是乎,我們又走了一遍提升公共模塊的流程。。。
為什么會(huì)出現(xiàn)這樣的問題?根本原因在于,我們無法事先規(guī)劃好所有的模塊,無法在一開始就對(duì)一個(gè)模塊的屬性清晰地劃分。這個(gè)問題也基本算是無解。矛盾在于,我們對(duì)模塊進(jìn)行了私有和公有的屬性劃分,卻無法事先掌握所有的模塊屬性,只能走一步算一步,錯(cuò)了就回來再改改。
解決這問題的辦法是,取消對(duì)模塊的屬性劃分,所有模塊都默認(rèn)為公共模塊,可以隨時(shí)取用。但是這樣就倒退回了我們之前的那種情況,所有的模塊都是m-*,且都扎堆在common里,導(dǎo)致common的體積過大,所以這個(gè)問題只能到這里為止了。
模塊
如何界定一個(gè)模塊?或者說,怎么樣才能把一部分代碼劃分為一個(gè)模塊?劃分的依據(jù)是什么?這是我們接下去要探討的問題。
設(shè)計(jì)原則
我們說模塊是一個(gè)功能相對(duì)獨(dú)立且完整的結(jié)構(gòu)體,其實(shí)這應(yīng)該是 組件 的概念,我們這里只從css的范圍內(nèi)來探討模塊化,那么模塊的定義就可以縮窄到:一個(gè)(組)樣式相對(duì)獨(dú)立且完整的類。比如:
/* copy_right */
.m-copy_right {
color: #ccc;
background: #666;
font-size: 14px;
text-align: center;
padding: 20px 0;
line-height: 1.8;
}
/* nav */
.m-nav {
color: #ccc;
background: #666;
font-size: 14px;
}
.m-nav .u-logo { ... }
.m-nav .list { ... }
.m-nav .list .item { ... }
原則上來講,一個(gè)css模塊應(yīng)該遵循以下幾點(diǎn)要求:
- 只對(duì)外暴露一個(gè)類名;
/**
* 正確示范,所有模塊相關(guān)的代碼都掛在模塊的選擇器名下
*/
.m-nav { ... }
.m-nav .list { ... }
.m-nav .list .item { ... }
/**
* 錯(cuò)誤示范,暴露了.m-nav和.list兩個(gè)類名,污染了空間
*/
.m-nav { ... }
.list { ... }
.list .item { ... }
- 不影響周圍布局:一般情況下,盡量不要使用一個(gè)脫離文檔流的布局(既使用了float:left/right,position:absolute/fixed的布局),盡量不要使用外邊距(margin)。這是為了使得模塊更加穩(wěn)定、具備更高的可塑性;
/**
* 正確示范,在common中定義一個(gè)模塊,在頁面css中對(duì)模塊進(jìn)行定位和偏移
*/
/* common */
.u-logo {
width: 100px;
height: 100px;
}
.cm-news {
width: 200px;
height: 100px;
}
/* index */
.u-logo {
position: absolute;
left: 20px;
top: 20px;
}
.cm-news {
margin-top: 50px;
}
/**
* 錯(cuò)誤示范,在common中定義一個(gè)模塊并固定它的位置
*/
/* common */
.u-logo {
width: 100px;
height: 100px;
position: absolute;
left: 20px;
top: 20px;
}
.cm-news {
width: 200px;
height: 100px;
margin-top: 50px;
}
- 模塊盡量設(shè)計(jì)為方便復(fù)用的量級(jí),避免大而全,求精巧;
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<div class="g-index">
<div class="g-bd">
<!-- 正確的示范 -->
<!-- 創(chuàng)建一個(gè)大的內(nèi)容塊article_box,而不是一個(gè)大模塊 -->
<div class="article_box">
<div class="hd">
最新文章
</div>
<div class="bd">
<div class="list">
<!-- 這里我們把每一個(gè)項(xiàng)作為可復(fù)用的私有模塊 -->
<div class="m-list_item">
<img class="cover" />
<div class="info">
<div class="title">
<a href="#">文章標(biāo)題</a>
</div>
<div class="desc">文章簡(jiǎn)介</div>
</div>
</div>
</div>
</div>
<div class="ft">
<!-- 這里我們直接引入了一個(gè)公共分頁模塊 -->
<div class="cm-page">
<a href="#" class="pg">1</a>
<a href="#" class="pg">2</a>
<a href="#" class="pg">3</a>
<a href="#" class="pg">4</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<div class="g-index">
<div class="g-bd">
<!-- 錯(cuò)誤的示范 -->
<!-- 創(chuàng)建一個(gè)龐大且不可復(fù)用的私有模塊m-article_box -->
<div class="m-article_box">
<div class="hd">
最新文章
</div>
<div class="bd">
<div class="list">
<div class="item">
<img class="cover" />
<div class="info">
<div class="title">
<a href="#">文章標(biāo)題</a>
</div>
<div class="desc">文章簡(jiǎn)介</div>
</div>
</div>
</div>
</div>
<div class="ft">
<div class="page">
<a href="#" class="pg">1</a>
<a href="#" class="pg">2</a>
<a href="#" class="pg">3</a>
<a href="#" class="pg">4</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
值得注意的是,這里的原則第三點(diǎn),并不只是出于css模塊化的考慮,事實(shí)上這更適用于 組件化 的設(shè)計(jì)思路,這在后面講組件化的時(shí)候我們會(huì)提到。
繼承
css的繼承也是很簡(jiǎn)單的,一般來說是有這么幾種方式:
- 在css中并寫兩個(gè)類,如
.cm-nav, .m-nav,我們知道,這相當(dāng)于讓兩個(gè)(組)類共享一套樣式,然后我們?cè)賳为?dú)對(duì).m-nav進(jìn)行補(bǔ)充,實(shí)現(xiàn)繼承和定制; - 在class屬性里并寫兩個(gè)類,如
<img class="u-logo logo">,這樣我們只需要在頁面css中單獨(dú)對(duì).logo類進(jìn)行補(bǔ)充,就可以實(shí)現(xiàn)定制; - 在頁面css中直接對(duì)類進(jìn)行引用
,然后補(bǔ)充樣式,實(shí)現(xiàn)定制,如.cm-nav { margin-bottom: 20px; };
……
(還有許多黑魔法,歡迎補(bǔ)充)
第一種在我們這套模式里是不可取的,因?yàn)槲覀兊墓材K都是放在common里,不可能每繼承一次就上去補(bǔ)一個(gè)類;
第二種可取,但是需要多一個(gè)近似的類名,不提倡;
第三種又簡(jiǎn)單又靠譜。
/* common.css */
body {
background: #fff;
color: #333;
font-size: 16px;
}
.cm-nav {
width: 100%;
height: 50px;
color: #fff;
background: #333;
}
我們?cè)陧撁鎐ss可以這樣用:
/* index.css */
.g-index {
background: #fff;
color: #333;
font-size: 16px;
}
.cm-nav {
width: 1000px; /* 樣式覆蓋 */
margin: auto; /* 樣式增加 */
}
狀態(tài)
我們?cè)谏厦嬷v前綴的時(shí)候,提到過一個(gè)前綴z-,我們說它可以用來表示狀態(tài)。一個(gè)模塊是可以有 狀態(tài) 的,當(dāng)然,這里說的不是狀態(tài)好狀態(tài)差的意思(模塊還成精了~),這里指的是有多種表現(xiàn)形式,我們舉例來說,一個(gè)彈窗模塊m-dialog,它應(yīng)該至少具備兩種狀態(tài):顯示和隱藏(關(guān)閉)。我們用關(guān)鍵字 active 來表示這兩種狀態(tài),添加z-active類表示顯示,不加表示隱藏。如下:
/* index.css */
.m-dialog {
display: none;
}
.m-dialog.z-active {
display: block;
}
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<div class="g-index">
<div class="g-bd">
<div class="m-dialog">
這是一個(gè)未激活的彈窗,你看不到!
</div>
<div class="m-dialog z-active">
這是一個(gè)已激活的彈窗,你看得到!
</div>
</div>
</div>
</body>
</html>
彈窗一個(gè)比較有代表性的例子,另一個(gè)典型的例子是按鈕,用過bootstrap的人都知道,按鈕btn只需要相對(duì)應(yīng)添加幾個(gè)狀態(tài)類,就可以有不同的配色方案,應(yīng)付不同的場(chǎng)景需要,這其實(shí)就是我們的z-的含義。z-是很常用的,我們應(yīng)該把我們的模塊設(shè)計(jì)得盡量滿足多種可預(yù)見的需求,而不是每次都在頁面去定制和覆蓋基本樣式。
總結(jié)
到目前為止,我們已經(jīng)定制了一套基于規(guī)范的css模塊化生產(chǎn)方式,雖然并不完美,但這卻也是一套簡(jiǎn)單的、零工具、零成本的解決方案,適用于任何項(xiàng)目。
可以看出,我們這里所謂的模塊化,其實(shí)是規(guī)范化的子集,通過制定了一套規(guī)范,才產(chǎn)生了模塊。所以css的模塊化過程其實(shí)是css規(guī)范化的過程。
事實(shí)上,由于css本身并不是一門語言,不具備語言的特性,我們只有借助其他方式和工具,才能達(dá)到模塊化的目的。而目前為止,我們還只是停留在規(guī)范的約束方式上,內(nèi)容看起來比較low :),沒關(guān)系,下一節(jié)我們會(huì)開始介紹【css預(yù)處理語言的模塊化實(shí)踐】。要知道,對(duì)于早已習(xí)慣sass編程的我,也是悶著一大口氣好不容易才寫到了這里的。。。
想必你也留意到了文中多處提到“手打css”這一說法,其實(shí)這只是對(duì)傳統(tǒng)css編程方式的一種戲稱,說實(shí)話有哪種編程不是手打的,難不成用腳么?哈哈。但是說實(shí)話,有了css預(yù)處理,模塊化才能算得上真正意義的模塊化,模塊化的意義才凸顯出來,因?yàn)槲覀兯械乃伎寂c努力,機(jī)關(guān)算盡,最終的目的都只有一個(gè)——提高工作效率。
預(yù)告
css預(yù)處理語言的出現(xiàn)是一個(gè)十分重要的階段,它直接推進(jìn)了css的發(fā)展,改變了長久以來css的編程方式。
我們來瞥一眼sass:
// index.scss
@import './common/normalize';
@import './common/common';
@import './common/mixin';
.g-index {
@include m-nav;
@include m-news;
@include m-copy_right;
.g-hd {
.m-nav {
width: 100px;
margin: auto;
}
}
.g-bd {
.m-news {
margin-top: 20px;
}
}
.g-ft {
.m-copy_right {
width: 100px;
margin: auto;
}
}
}
sass的選擇器嵌套寫法是不是亮瞎雙眼?文件直接導(dǎo)入是不是很方便?還有變量?還能寫函數(shù)???
下一節(jié),【css預(yù)處理語言的模塊化實(shí)踐】我們來看css預(yù)處理語言如何使模塊化更加美好。