如何寫出一套可維護的CSS庫?

前言

如何寫出一套可維護的CSS庫?不妨談談CSS的設計模式/架構吧。接下來將爲你講述三個主流的CSS設計思想和一個最近通用的CSS設計思想:OOCSS、SMACSS、BEMCSS、METACSS。css

OOCSS

OOCSS,字面意思是面向對象的CSS,是由Nicole Sullivan提出的css理論,雖然說是理論,實則更像一種程序員間約定的規範:html

  • Separate structure and skin(分離結構和主題)減小對 HTML 結構的依賴
  • Separate container and content(分離容器和內容)增長樣式的複用性

在 OOCSS 的觀念中,強調重複使用 class,而應該避免使用 id 做爲 CSS 的選擇器。 OOCSS追求元件的複用,其class命名更爲抽象,通常不體現具體事物,而注重表現層的抽取。前端

SMACSS

smacss經過一個靈活的思惟過程來檢查你的設計過程和方式是否符合你的架構程序員

設計的主要規範有三點:設計模式

  • Categorizing CSS Rules(爲css分類)
  • Naming Rules(命名規範)
  • Minimizing the Depth of Applicability(最小化適配深度)
Categorizing CSS Rules

這一點是SMACSS的核心。SMACSS認爲css有5個類別,分別是: 1 Base 2 Layout 3 Module 4 State 5 Theme or Skinmarkdown

Base Rules

基礎規範,描述的是任何場合下,頁面元素的默認外觀。它的定義不會用到class和ID。css reset也屬於此類。常見的如normalize.css,CSS Tools架構

Layout Rules

佈局規範,元素是有層次級別之分的,Layout Rules屬於較高的一層,它能夠做爲層級較低的Module Rules元素的容器。左右分欄、柵格系統等都屬於佈局規範。佈局是一個網站的基本,不管是左右仍是居中,甚至其餘什麼佈局,要實現頁面的基本瀏覽功能,佈局必不可少。SMACSS還約定了一個前綴l-/layout-來標識佈局的class。舉個最廣泛的例子。框架

.layout-header {}
.layout-container {}
.layout-sidebar {}
.layout-content {}
.layout-footer {}
複製代碼
Module Rules

模塊規範,模塊是SMACSS最基本的思想,同時也是大部分CSS理論的基本,將樣式模塊化就能達到複用和可維護的目的,可是SMACSS提出了更具體的模塊化方案。SMACSS中的模塊具備本身的一個命名,隸屬於模塊下的類皆以該模塊爲前綴,例子以下:dom

.todolist{}
.todolist-title{}
.todolist-image{}
.todolist-article{}
複製代碼

能夠看到todolist做爲一個模塊,包含了title,image,article等組件,同時還能夠加上如.todolist-background-danger等修飾類,在模塊內可使用其名稱作前綴任意組織模塊結構,但目的是讓其變得更易用,提升可擴展性和靈活度,若是隻是爲了修飾而修飾,寫出大量沒有任何複用性的類,即是一種弄巧成拙的作法。ide

State Rules

狀態規範,這個應該不少前端開發者都很好理解,描述的是任一元素在特定狀態下的外觀。例如,一個消息框可能有success和error等狀態。與OOCSS抽取修飾類的方式的不一樣,SMACSS是抽取更高級別的樣式類,獲得更強的複用性,如隱藏某個元素的寫法:

.is-hidden{
    display: none;
}
複製代碼
Theme Rules

主題規範,描述了頁面主題外觀,通常是指顏色、背景圖。Theme Rules能夠修改前面4個類別的樣式,且應和前面4個類別分離開來(便於切換,也就是「換膚」)。SMACSS的Theme Rules不要求使用單獨的class命名,也就是說,你能夠在Module Rules中定義.header{ }而後在Theme Rules中也用.header { }來定義須要修改的部分(後加載覆蓋前加載樣式內容)

Naming Rules

命名規範

按照前面5種的劃分:

Base Rules(Pass)

Layout Rules用l-或layout-這樣的前綴,例如:.l-header、.l-sidebar。

Module Rules用模塊自己的命名,例如圖文排列的.media、.media-image。

State Rules用is-前綴,例如:.is-active、.is-hidden。

Theme Rules若是做爲單獨class,用theme-前綴,例如.theme-a-background、.theme-a-shadow。

Minimizing the Depth of Applicability

最小適配深度原則,簡單的例子:

/* depth 1 */
.sidebar ul h3 { }

/* depth 2 */
.sub-title { }
複製代碼

兩段css的區別在於html和css的耦合度(這一點上和OOCSS的分離容器和內容的原則不謀而合)。能夠想到,因爲上面的樣式規則使用了繼承選擇符,所以對於html的結構實際是有必定依賴的。若是html發生重構,就有可能再也不具備這些樣式。對應的,下面的樣式規則只有一個選擇符,所以不依賴於特定html結構,只要爲元素添加class,就能夠得到對應樣式。

固然,繼承選擇符是有用的,它能夠減小因相同命名引起的樣式衝突(常發生於多人協做開發)。可是,咱們不該過分使用,在不形成樣式衝突的容許範圍以內,儘量使用短的、不限定html結構的選擇符。這就是SMACSS的最小化適配深度的意義。

BEMCSS

BEM 分別表明着:Block(塊)、Element(元素/子塊/組成部分)、Modifier(修飾符),是一種組件化的 CSS 命名方法和規範,由俄羅斯 Yandex 團隊所提出。其目的是將用戶界面劃分紅獨立的(模)塊,使開發更爲簡單和快速,利於團隊協做開發。

特色

組件化/模塊化的開發思路。 書寫方式解耦化,不會形成命名空間的污染,如:.xxx ul li 寫法帶來的潛在嵌套風險。 命名方式化扁平,避免樣式層級過多而致使的解析效率下降,渲染開銷變大。 組件結構獨立化,減小樣式衝突,能夠將已開完成的組件快速應用到新項目中。 有着較好的維護性、易讀性、靈活性。 規則

BEM的命名模式在社區中有着不一樣方式,如下爲 Yandex 團隊所提出的命名規則爲(本文中的代碼使用該規則):

.[Block 塊]__[Element 元素]_[Modifier 修飾符] 不一樣的命名模式,區別在於BEM之間的鏈接符號不一樣,依我的而定:

.[Block 塊]__[Element 元素]--[Modifier 修飾符] 任何一種規範,都是基於實際需求而定,便於團隊開發和維護擴展,每一個規範都是通過合理評估後所得出的一種「思路」和「建議」。

Block(塊)

是一個獨立的實體,即一般所說的模塊或組件。

例:header、menu、search

規則 塊名需能清晰的表達出,其用途、功能或意義,具備惟一性。 塊名稱之間用-鏈接。 每一個塊名前應增長一個前綴,這前綴在 CSS 中有命名空間(如:m-、u-、分別表明:mod 模塊、ui 元件)。 每一個塊在邏輯上和功能上都相互獨立。 因爲塊是獨立的,能夠在應用開發中進行復用,從而下降代碼重複並提升開發效率。 塊能夠放置在頁面上的任何位置,也能夠互相嵌套。 同類型的塊,在顯示上可能會有必定的差別,因此不要定義過多的外觀顯示樣式,主要負責結構的呈現。 這樣就能確保塊在不一樣地方複用和嵌套時,增長其擴展性。 綜上所述,最終咱們能夠把BEM規則最終定義成:

.[命名空間]-[組件名/塊]__[元素名/元素]--[修飾符] 情景 須要構建一個 search 組件。

寫法 .m-search{} 結構

若是打算開發一套框架,可使用具備表明性的縮寫,用來表示命名空間:Element UI(el-)、Ant Design(ant-)、iView(ivu-)。
Element(元素)

是塊中的組成部分,對應塊中的子元素/子節點。

例:header title、menu item、list item

規則 元素名需能簡單的描述出,其結構、佈局或意義,而且在語義上與塊相關聯。 塊與元素之間用__鏈接。 不能與塊分開單獨使用。 塊的內部元素,都被認爲是塊的子元素。 一個塊中元素的類名必須用父級塊的名稱做爲前綴,所以不能寫成:block__elem1__elem2。 情景 search 組件中包含 input 和 button,是列表中的一個子元素。

寫法 .m-search{} .m-search__input{} .m-search__button{} 結構

<!-- search 組件 -->
<form class="m-search">
    <!-- input 是 search 組件的子元素 -->
    <input class="m-search__input">
    <!-- button 是 search 組件的子元素 -->
    <button class="m-search__button">Search</button>
</form>
複製代碼

原則上書寫時不會出現兩層以上的嵌套,全部樣式都爲平級,嵌套只出如今 .m-block_active ,狀態激活時的狀況。

Modifier(修飾符)

定義塊和元素的外觀、狀態或類型。

例:color、disabled、size

規則 修飾符需能直觀易懂表達出,其外觀、狀態或行爲。 修飾符用_鏈接塊與元素。 修飾符不能單獨使用。 在必要時可進行擴展,書寫成:block__elem_modifier_modifier,第一個modifier表示其命名空間。 情景 假定 search 組件有多種外觀,咱們選擇其中一種。而且在用戶未輸入內容時,button 顯示爲禁用樣式。

寫法 .m-search{} .m-search_dark{} .m-search__input{} .m-search__button{} .m-search__button_disabled{} 結構

<!-- dark 代表 search 組件的外觀 -->
<form class="m-search m-search-form_dark">
    <input class="m-search__input">
    <!-- disabled 代表 search__button 的狀態 -->
    <button class="m-search__button m-search__button_disabled">Search</button>
</form>
複製代碼
小結

不少人以爲 BEM 寫法難看,審美本是「智者見智,仁者見仁」的事。剛剛接觸多是會以爲有點奇怪,但全部東西都有一個適應過程。若是僅僅爲了好看,規避其優勢,我認爲得不償失。我的建議能夠嘗試使用 BEM 規範來書寫代碼。

BEM 命名會使得 Class 類名變長,但通過 GZIP 等壓縮後,文件的體積其實並沒有太大影響。

就和早年提出 CSS語義化 同樣,不要爲了語義而去語義,語義化自己的做用就是幫助你們更好的識別代碼,全部的規範都是基於項目的發展和團隊的協做,團隊能夠根據成員的意願選擇最合適的方式。

METACSS

一些寫在全局的通用方法,是SMACSS中通用方法思想的分支,通常以css屬性、Emmet css縮寫或功能來命名,一般以一個css屬性爲一個單位

表示屬性的:

.df { display: flex; }
複製代碼

表示功能的:

.tcut {  
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  }
複製代碼

以此類推,封裝好放到全局來使用,快速添加屬性來開發頁面。

我的總結

smacss覆蓋了全部的細節點;bemcss着重css的命名和語義化;oocss着重可複用,把每個dom節點當成一個對象,是css返璞歸真的思想;metacss着重快速開發快速添加屬性,顆粒度更細,經過在html代碼中添加類名來添加屬性,沒必要再去找相對應的選擇器中的css代碼來修改樣式。

相關文章
相關標籤/搜索