CSS進(jìn)階:提高你前端水平的4個(gè)技巧
譯者注:隨著 Node.js 、react-native 等技術(shù)的不斷出現(xiàn),和互聯(lián)網(wǎng)行業(yè)的創(chuàng)業(yè)的層出不窮,了解些前端知識(shí),成為全棧攻城師,快速的產(chǎn)出原型,展示你的創(chuàng)意,對(duì)程序員,尤其是在創(chuàng)業(yè)的程序員來說,越來越重要,下面我們就跟隨著名國外開發(fā)者網(wǎng)站上的熱推文章《Leveling up in CSS》,從提升你的CSS技巧開始。
CSS 在剛開始學(xué)習(xí)的時(shí)候看起來非常簡單。畢竟,它僅僅就是些樣式而已,事實(shí)上是這樣嗎?
但是,隨著你的不斷了解。很快,你會(huì)發(fā)現(xiàn) CSS 沒你想象的那么簡單,它復(fù)雜且有深度。
做好這四件事情,能讓你在大規(guī)模使用 CSS 的時(shí)候保證代碼的健壯性:使用適當(dāng)?shù)恼Z義,模塊化,采用統(tǒng)一的命名規(guī)范,遵循單一功能原則。
使用適當(dāng)?shù)恼Z義
在 HTML 和 CSS 編程中有語義標(biāo)注的概念。語義是指單詞的含義和他們間的關(guān)系。在 HTML 編程中,意味著你需要使用一個(gè)合適的標(biāo)簽名字來標(biāo)記。下面是一個(gè)經(jīng)典的例子。
- <!-- bad -->
- <div class=”footer”></div>
- <!-- good -->
- <footer></footer>
富有語義的 HTML 是非常簡單明確的。另一方面,富有語義的 CSS 則是更抽象和主觀的。編寫富有語義的 CSS 意味著在選擇類型的時(shí)候,類名要傳達(dá)出結(jié)構(gòu)和功能信息。類名要很容易被理解。確保它們不要太具體、太特殊。這樣,你就可以復(fù)用它了。
為了闡述什么是一個(gè)良好的類名,請(qǐng)看這個(gè)簡化了的 Medium 網(wǎng)站的 CSS 例子。
- <div class="stream">
- <div class="streamItem">
- <article class="postArticle">
- <div class="postArticle-content">
- <!-- content -->
- </div>
- </article>
- </div>
- </div>
通過這些代碼,你可以立即識(shí)別出它們的結(jié)構(gòu)、功能和含義。父節(jié)點(diǎn)的類名是 stream ,內(nèi)容是一個(gè)文章列表。它的子節(jié)點(diǎn)的類名是 streamItem ,內(nèi)容是文章列表中的一篇具體的文章。這使我們很容易的了解到父節(jié)點(diǎn)和子節(jié)點(diǎn)之間的關(guān)系。并且,這些類可以在每一個(gè)有文章功能的頁面中使用。
你可以像閱讀一本書一樣讀 HTML 和 CSS。它會(huì)給你講一個(gè)故事。通過故事你可以了解故事中的每一個(gè)角色和他們之間的關(guān)系。語義豐富的 CSS 代碼容易理解,更便于維護(hù)。
若果你想進(jìn)一步了解語義相關(guān)的內(nèi)容,看看 《怎么富有語義的為類命名》、《CSS 命名不簡單》 和 《富有語義和容易識(shí)別(的代碼命名)》,再看 《關(guān)于 HTML 命名和前端架構(gòu)》。
模塊化
在這個(gè)充滿了組件庫(以 React 為例)的時(shí)代,模塊化就是王者。組件就是由已經(jīng)解構(gòu)了的接口創(chuàng)建的可組合的模塊。下面是一個(gè)Product Hunt(一種發(fā)布好的創(chuàng)業(yè)項(xiàng)目的網(wǎng)站)前端頁面。作為練習(xí),讓我們將這個(gè)頁面分解成一系列的組件。
每種顏色框代表一個(gè)組件,stream 節(jié)點(diǎn)下分為好多個(gè) stream item 子節(jié)點(diǎn)。
- <div class="stream">
- <div class="streamItem">
- <!-- product info -->
- </div>
- </div>
大多數(shù)組件都可以分解為更小的組件。
每一個(gè) stream item 組件都有一個(gè)縮略圖和一個(gè)特色的產(chǎn)品信息。
- <!-- STREAM COMPONENT -->
- <div class="stream">
- <div class="streamItem">
- <!-- POST COMPONENT -->
- <div class="post">
- <img src="thumbnail.png" class="postThumbnail"/>
- <div class="content">
- <!-- product info -->
- </div>
- </div>
- </div>
- </div>
由于 stream 組件和它的子控件是完全獨(dú)立的,你可以很容易的調(diào)整或者更換 post 組件,并且這不會(huì)對(duì) stream 組件產(chǎn)生任何影響。
使用組件的思想將會(huì)使你的代碼解耦。解耦的代碼越多,你的類之間的依賴就越低。這會(huì)讓你的代碼更容易修改,并且使你的代碼更長時(shí)間的工作下去而不用修改它。
組件驅(qū)動(dòng)設(shè)計(jì)
模塊化你的 CSS 時(shí),首先將你的設(shè)計(jì)分解成多個(gè)組件。你可以使用紙和筆,也可以使用類似 Illustrator 或者 Sketch 這類的軟件。確定你將要如何命名這些組件,同時(shí)理清各個(gè)組件之間的關(guān)系。
閱讀更多關(guān)于 CSS 組件驅(qū)動(dòng)的文章,詳見《CSS 建構(gòu):可擴(kuò)展和模塊化處理》、《使用 Sass 編寫模塊化的 CSS》和《模塊化你的前端代碼——編寫高可維護(hù)和條理清晰的代碼》。
采用統(tǒng)一的命名規(guī)范
目前有幾十個(gè)不同版本的 CSS 命名規(guī)范。有些人對(duì)他們選擇的命名規(guī)范極其篤定,認(rèn)為他們的比別人的更好。事實(shí)上,不同的人喜歡不同的命名規(guī)范。我聽到的***的建議是:選擇你覺得最合適的命名規(guī)范。
下面簡單列舉一下常用的命名規(guī)范:
- Object oriented CSS OOCSS
- Block element modifier (BEM)
- Scalable and modular architecture for CSS (SMACSS)
- Atomic
我最喜歡的命名規(guī)范是 BEM。BEM 代表塊(block)、元素(element)和修飾符(modifier)。Yandex,在俄羅斯的相當(dāng)于谷歌的搜索引擎,為了解決他們 CSS 代碼庫中的縮放問題而提出了它(它指BEM)。
BEM 是一個(gè)極其簡單——又極其嚴(yán)格——的命名規(guī)范。
- .block {}
- .block__element {}
- .block--modifier {}
塊(Blocks)代表高級(jí)別的類。元素(Elements)是塊的子模塊。修飾符(modifiers)代表不同的狀態(tài)。
- <div class="search">
- <input type="search__btn search__btn--active" />
- </div>
在上面的示例中, search 是塊(block),search button是它的元素(element)。如果你想要更改按鈕的狀態(tài),我們可以為按鈕增加一個(gè)修飾符,例如 active 。
關(guān)于命名規(guī)范要記住的一件事是,無論你喜歡哪種命名規(guī)范,你會(huì)經(jīng)常繼承或者工作在不同標(biāo)準(zhǔn)的代碼庫上。請(qǐng)敞開心扉去學(xué)習(xí)新的標(biāo)準(zhǔn),用不同的思維去思考 CSS 。
你可以在《深入學(xué)習(xí) BEM 語法》、《BEM 101》和《BEM 簡介》上看到更多關(guān)于 BEM 的信息。想要了解不同的命名規(guī)范,參見《OOCSS、ACSS、BEM、SMACSS:這些是什么?我該用哪個(gè)?》。
遵循單一功能原則
單一功能原則規(guī)定每個(gè)模塊和類都應(yīng)該有一個(gè)單一的功能,并且該功能應(yīng)該由這個(gè)類完全封裝起來。
在 CSS 中,單一功能原則代表每一段代碼、類和模塊只做一件事。當(dāng)我們提交 CSS 文件時(shí),這意味著每個(gè)獨(dú)立的組件(例如輪播效果和導(dǎo)航欄)都應(yīng)該有自己的 CSS 文件。
- /components
- |- carousel
- |- |- carousel.css
- |- |- carousel.partial.html
- |- |- carousel.js
- |- nav
- |- |- nav.css
- |- |- nav.partial.html
- |- |- nav.js
另外一個(gè)常見的組織文件的方式是按照功能將文件分組。舉個(gè)栗子,如上面所示,所有和輪播效果組件有關(guān)的文件都被分類到了一起。采用這種方式可以讓你更容易的找到相關(guān)文件。
除了對(duì)組件的樣式進(jìn)行分離之外,***利用單一功能原則對(duì)全局樣式也進(jìn)行分離。
- /base
- |- application.css
- |- typography.css
- |- colors.css
- |- grid.css
在這個(gè)例子中,每個(gè)相關(guān)的樣式被分離到自己的樣式文件中。這樣,如果你想要修改樣式中的顏色,那么你將會(huì)很容易的找到它。
無論你使用哪種方式組織文件結(jié)構(gòu),盡量在決定的時(shí)候參考單一功能原則。一旦有某個(gè)文件開始變的臃腫,那么考慮按照邏輯功能將它分成多個(gè)部分。
更多有關(guān)組織文件結(jié)構(gòu)和 CSS 架構(gòu)的文章,詳見《Sass 審美 1:架構(gòu)和組織樣式文件》和《可擴(kuò)展和可維護(hù)的 CSS 架構(gòu)》。
當(dāng)單一功能原則應(yīng)用于你的每一個(gè) CSS 類選擇器中時(shí),這意味著每一個(gè)類選擇器都有著唯一的功能。換句話說,要根據(jù)不同關(guān)注點(diǎn)將樣式分離到不同的類選擇器中。下面是個(gè)經(jīng)典的例子:
- .splash {
- background: #f2f2f2;
- color: #fffff;
- margin: 20px;
- padding: 30px;
- border-radius: 4px;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- }
在上面的例子中,我們將關(guān)注點(diǎn)耦合了。splash 這個(gè)類不但包含了本身的樣式和邏輯,同時(shí)也包含了它的子節(jié)點(diǎn)的。為了解決這個(gè)問題,我們可以將這段代碼分離為兩個(gè)新的類。
- .splash {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- }
現(xiàn)在我們有 splash 和 splash content 兩個(gè)類。我們可以將 splash 作為一個(gè)一般的全屏類,它可以擁有任何子節(jié)點(diǎn)。所有子節(jié)點(diǎn)關(guān)注的屬性,都在 splash content 中,與父節(jié)點(diǎn)的屬性是完全解耦的。
你可以通過閱讀下列文章進(jìn)一步了解單一功能原則在樣式表和類中的應(yīng)用。《單一功能原則在 CSS 中的應(yīng)用》和《單一功能原則》。
簡單勝過復(fù)雜
如果你問任何一個(gè)成功的前端開發(fā)工程師或者 CSS 架構(gòu)師,他們會(huì)告訴你,他們從來沒有對(duì)自己的代碼完全滿意。寫好 CSS 是一個(gè)不斷迭代的過程。從簡單開始,遵循基本的 CSS 規(guī)則和樣式指南,然后不斷迭代。
我很想知道你的 CSS 學(xué)習(xí)之路。你喜歡的命名規(guī)范是什么?你是怎樣組織你的代碼文件的?你可以隨時(shí)通過留言或者在 Tweet 上告訴我。