Philip Walton 在AppFolio擔任前端工程師,他在Santa Barbara on Rails的聚會上提出了CSS架構(gòu)和一些最佳實踐,并且在工作中一直沿用。
擅長CSS的Web開發(fā)人員不僅可以從視覺上復(fù)制實物原型,還可以用代碼進行完美的呈現(xiàn)。無需使用表格、盡可能少的使用圖片。如果你是個名副其實的高手,你可以快速把最新和最偉大的技術(shù)應(yīng)用到你的項目中,比如媒體查詢、過渡、濾鏡、轉(zhuǎn)換等。雖然這些都是一個真正的CSS高手所具備的,但CSS很少被人單獨拿出來討論,或者用它去評估某個人的技能。
有趣的是,我們很少這樣去評價其他語言。Rails開發(fā)人員并不會因為其代碼比較規(guī)范,就認為他是一名優(yōu)秀的開發(fā)人員。這僅僅是個基準。當然,他的代碼得必須規(guī)范。另外,還需集合其他方面考慮,比如代碼是否可讀?是否容易修改或擴展……
這都是些很自然的問題,CSS和它們并沒有什么不同之處。今天的Web應(yīng)用程序要比以往更加龐大。一個缺乏深思熟慮的CSS架構(gòu)往往會削弱發(fā)展,是時候像評估其他語言那樣,來評估一下CSS架構(gòu)了,這些都不應(yīng)該放在“事后”考慮或者單單屬于設(shè)計師們的事情。
1.良好的CSS架構(gòu)目標
在CSS社區(qū),很難提出某個最佳實踐已經(jīng)成為大家的普遍共識。純粹地從Hacker News的評論上判斷和開發(fā)者們對CSS Lint發(fā)布后的反應(yīng)來看,大多數(shù)人對基本的CSS東西是持反對意見的。所以,并不是為自己的最佳實踐奠定一套基本的論據(jù),而應(yīng)該確定真正的目標。
好的CSS架構(gòu)目標并不同于開發(fā)一個好的應(yīng)用程序,它必須是可預(yù)測、可重用、可維護和可伸縮的。
可預(yù)測
可預(yù)測意味著可以像預(yù)期的那樣規(guī)范自己的行為。當你添加或者修改某個規(guī)則時,它并不會影響到?jīng)]有指定的部分。對于一個小網(wǎng)站來說,一些微乎其微的改變并不算什么。而對于擁有成千上萬個頁面的大網(wǎng)站來說,可預(yù)測卻是必須的。
可重用
CSS規(guī)則應(yīng)具備抽象和解耦性,這樣你就可以在現(xiàn)有的基礎(chǔ)上快速構(gòu)建新的組件,無需重新修改編碼模式。
可維護
當把新組件放置到網(wǎng)站上,并且執(zhí)行添加、修改或者重新設(shè)計操作時,無需重構(gòu)現(xiàn)有CSS,并且新添加的X并不會打破原有頁面的Y組件。
可擴展
當網(wǎng)站發(fā)展到一定規(guī)模后,都需要進行維護和擴展。可擴展的CSS意味著網(wǎng)站的CSS架構(gòu)可以由個人或者團隊輕易地管理,無需花費太多的學習成本。
2.常見的錯誤實踐
在實現(xiàn)良好的CSS架構(gòu)目標之前,我們來看一些常見的錯誤做法,這對我們達成目標是有好處的。
下面的這些例子雖然都可以很好的執(zhí)行,但卻會給你帶來很多煩惱,盡管我們的意圖和愿望都是美好的,但是這些開發(fā)模式會讓你頭疼。
幾乎在每個網(wǎng)站上,都會有一個特定的虛擬元素看起來與其他頁面是完全一樣的,然而只有一個頁面除外。當面對這樣一種情況時,幾乎每個新手CSS開發(fā)人員(甚至是經(jīng)驗豐富的)都會以同樣的方式來修改。你應(yīng)該為該頁面找出些與眾不同之處(或者自己創(chuàng)建),然后再寫一個新規(guī)則去操作。
基于父組件來修改組件
.widget {
background: yellow;
border: 1px solid black;
color: black;
width: 50%;
}
#sidebar .widget {
width: 200px;
}
body.homepage .widget {
background: white;
}
初看,這絕對是段無害的代碼,但讓我們來看看它是否達到了我們所設(shè)置的目標。
首先,widget在examle是不可預(yù)見的。當這些小部件出現(xiàn)在頁面兩側(cè)或者主頁面時,開發(fā)人員期望它們以某種特定的方式顯示出來,且又不失特色。另外,它也是不可重用或不可擴展的。
另外,它也比較難維護。一旦這個widget需要重新設(shè)計,那么你不得不修改其他幾個CSS樣式。想象一下,如果這段代碼是使用其他語言編寫的,它基本就是一個類定義,然后在代碼的另一部分使用該類定義并做出擴展。這直接違反了軟件開發(fā)的開放/閉合(open/close)原則。
過于復(fù)雜的選擇器
偶爾,會有些文章介紹CSS選擇器對整個網(wǎng)站的展示起著非常重要的作用,并且宣稱無需使用任何類選擇器或者ID選擇器。
但伴隨著越深入的開發(fā),我越會遠離這種復(fù)雜的選擇器。一個選擇器越復(fù)雜,與HTML就越耦合。依靠HTML標簽和組合器可以保持HTML代碼干干凈凈,但卻讓CSS更加毛重和凌亂。
#main-nav ul li ul li div { }
#content article h1:first-child { }
#sidebar > div > h3 + p { }
對上面代碼進行簡單的理解。第一個可能是對下拉菜單進行樣式化;第二個想說明文章的主標題應(yīng)該與其他頁面的H1元素不同;最后一個表示在第一段的側(cè)邊欄區(qū)域添加一些額外的空間。
如果這個HTML是永遠不變的,那就無可說之處,但這根本毫不現(xiàn)實。過于復(fù)雜的選擇器會讓人印象深刻,它可以讓HTML擺脫掉表面上的復(fù)雜,但對于實現(xiàn)良好的CSS架構(gòu)目標卻毫無用處。
上面提到的例子都是不具備可預(yù)測性、可重用、可擴展和可維護這四大特性的。例如第一個選擇器(下來菜單)例子,如果一個外觀非常相似的下拉列表需要用在不同的頁面上,并且#main-nav并不屬于內(nèi)部元素,那么你是否需要重新設(shè)計?假設(shè)開發(fā)者想要修改第三個例子里div里面部分標記,那么整個規(guī)則都會被打破。
過于通用的類名
當創(chuàng)建可重用的設(shè)計組件時,在組件的類選擇器中覆蓋附件的子元素是很常見的現(xiàn)象。例如:
.widget {}
.widget .title {}
.widget .contents {}
.widget .action {}
像.title、.contents、.action這些子元素類選擇器可以被安全地進行樣式命名,無需擔心這些樣式會蔓延到擁有相同類名的其他元素中。這是千真萬確的。但它并沒有阻止相同樣式類名稱會蔓延到這個組件上。
在一些大型項目上,像.title這樣的名稱很有可能會被用在另外一個頁面或者本身。如果這樣的情況發(fā)生,那么整個標題部分明顯會和預(yù)期的不一樣。
過于通用的類選擇器名稱會導(dǎo)致許多不可預(yù)測的CSS樣式發(fā)生。