CSS方法論(一)

編寫CSS會遇到什麼問題?

其實CSS很好寫,只要知道css語法,你就可以寫出來,通過各種學習,你也可以做出一個很美麗的頁面。對能熟練編寫網頁的人來說,可以很簡單的將設計圖變成網頁。
但是在中型/大型項目中,你往往遇見的問題,並不是如何寫出一個網頁,而是:

  • 在前端框架內引入UI框架,是否能保證你的樣式與框架不產生衝突,怎麼解決
  • 是否能處理多人協作所產生的問題
  • 怎麼提高你的樣式的可維護性
  • 你的樣式是否可以複用,怎麼複用
  • 能不能提升幸福感

甚至於個人,怎麼讓你自己的代碼更優雅,讓自己更有成長,而不是僅僅在寫代碼。


CSS方法論

早在前幾年,社區就根據種種編寫CSS所遇到的問題,提出了一些方法論:

  • OOCSS
  • BEM
  • SMACSS
  • Atomic CSS

OOCSS(面向對象的CSS)

社區內最早提出的一種方法,也可以說是模塊化CSS的起源。由NicoleSullivan 於 2009 年提出,這基於她在雅虎的工作。

面向對象對於後端開發人員可能較爲熟悉,那麼在CSS中的面向對象是什麼?

面向對象:把數據及對數據的操作方法放在一起,作爲一個相互依存的整體——對象。對同類對象抽象出其共性,形成類。類中的大多數數據,只能用本類的方法進行處理。類通過一個簡單的外部接口與外界發生關係,對象與對象之間通過消息進行通信。程序流程由用戶在使用中決定。

CSS中的對象是一個可複用的樣式規則。

Basically, a CSS “object” is a repeating visual pattern, that can be abstracted into an independent snippet of HTML, CSS, and possibly JavaScript. That object can then be reused throughout a site.
-- OOCSS wiki

舉個簡單的例子,我們在一個網站中,很多頁面都需要使用到按鈕,那麼根據oocss的定義我們應該怎麼做?
在style中加入一個 btn 的類,之後網站內全部的按鈕都使用這個樣式。這個 btn 就是一個對象。

<style>
.btn {
    padding: 4px 8px;
    background-color: #bbb;
    color: #fff;
}
</style>
<button class="btn">按鈕</button>

在例子中我們定義了一個 btn 的css類。那麼這個css類就是一個對象。熟悉面向對象的朋友肯定知道,哦,我們把button這個對象封裝了。所以以後在網站中在使用按鈕,直接用 btn 這個類就可以了。

接下來我們來了解下,OOCSS包含了兩個原則:

  • 容器與結構分離(Separate container and content)
  • 內容與樣式分離(Separate structure and skin)

以及OOCSS的其他特點:

  • 使用類名來擴展基礎對象
  • 堅持語義化的命名方式

容器與結構分離

通常在我們寫CSS的時候,我們通常會根據Html元素的位置來規定樣式,例如:

<div class="nav">
    <ul>
        <li>列表1</li>
        <li>列表2</li>
        <li>列表3</li>
    </ul>
</div>
.nav ul li {...}

而在OOCSS認爲,我們的樣式不應該根據元素的位置來判斷對象的樣式。
而是應該給元素定義自己的樣式,如:

<div class="nav">
    <ul class="list">
        <li class="list-item">列表1</li>
        <li class="list-item">列表2</li>
        <li class="list-item">列表3</li>
    </ul>
</div>
.list {...}
.list-item {...}

也就是說,在網頁中的任何位置使用 list ,我都不需要考慮 list 的上下文是什麼,不論什麼情況下 list 的樣式都不應該改變。

內容與樣式分離

現在我們就遇到了新問題,在之前我們定義了一個 btn 對象,現在我想要再網頁中加入一個紅色的按鈕怎麼辦?
在學oocss之前我們可能說,在style改一下就好了,或者加一個紅顏色的對象就可以了;

.btn {
    padding: 4px 8px;
    background-color: #bbb;
    color: #fff;
}

.red-btn {
    padding: 4px 8px;
    background-color: red;
    color: #fff;
}

這樣修改的確是有一個紅色的按鈕,但是出現了什麼問題?

  • 我發現我寫兩遍的 padding: 4px 8px; 和 color: #fff;
  • 拿我現在想要綠色、藍色、橙色的按鈕怎麼辦,甚至我想要大一點的按鈕?

OOCSS提出了他的核心原則之一:內容與樣式分離,他將對象設置爲基本的樣式,而如果這個對象存在多種多樣的樣式,我們通過添加皮膚(skin)的方式給他添加樣式。

.btn{
   padding: 4px 8px;
   background-color: #bbb;
   color: #fff;
}

.red{
   background-color: red;
}
<button class="btn red">按鈕</button>

這樣我們要的紅色按鈕就出爐了,你們想要的綠色、藍色等等等等愛要什麼要什麼...

使用類名來擴展基礎對象

那麼在這個例子中,我們可以看到我們使用了一個紅色的按鈕,但是我們會發現一個問題,如果當我們寫了一個label的時候我們想讓他的字體是紅色的,我們如果不注意,樣式很有可能會衝突。

<button class="btn red">label按鈕</button>
<label class="label red">我是紅色的label</label>

在OOCSS中,提倡將對象的皮膚使用其基礎類名來進行拓展。

.btn {...}
.btn-red {...}
.label {...}
.label-red {...}

這樣我們一眼就可以看出,我們的擴展樣式是對應哪個對象的。也減少了樣式的衝突。

堅持語義化的命名方式

OOCSS還提倡使用語義化的命名方式,這樣有什麼好處呢?我們可以根據名稱給皮膚定義使用場景,在特定場景使用特定的皮膚,這樣就不需要擔心在網站中胡亂使用顏色了。

.btn {...}
.btn-edit{  background-color: blue;}
.btn-delete{  background-color: red;}

總結

如果對前端比較瞭解的同學可以發現,其實這個方法我們經常能使用得到,大名鼎鼎的Bootstrap就是使用了這種方法。
這種方法就是讓你的CSS代碼更靈活、更具有可複用性、可維護行及可擴展性。

BEM(Block-Element-Modifier)

什麼是BEM?

BEM代表塊(Block),元素(Element),修飾符(Modifier),由Yandex團隊提出的一種前端命名方法論。
BEM是一種讓你可以快速開發網站並對此進行多年維護的技術。 -- 早期描述
BEM是一種命名方法,能夠幫助你在前端開發中實現可複用的組件和代碼共享。

BEM是一個嚴格約定的命名規範,通過這種規範,來解決我們在編寫CSS是所遇到的問題。

BEM將網頁中的元素分爲塊、元素、修飾符

/* 書寫規範 */
.block {...} /* 塊 塊名*/
.block__element {...} /* 元素 塊名 + __ + 元素名 */
.block--modifier {...} /* 修飾符 塊名 + -- + 元素名 */
  • .block 塊:代表了更高級別的抽象或組件
  • .block__element 元素:代表 .block 的後代,用於形成一個完整的.block的整體
  • .block--modifier 修飾符:代表 .block 的不同狀態或不同版本

塊(Block)

我們可以將塊理解爲web應用中的組件或者模塊。
特點:

  1. 嵌套式的構造
    Block 可以被嵌套到任何其他 block 裏面去。例如,一個頭部 header 可以包含一個 logo 、一個搜索表單 form 和一個登錄 login 。
  2. 隨意放置
    Block 可以在一個頁面內任意移動,也可以在頁面之間或項目之間移動。Block 作爲獨立的實體來實現,這使得在頁面上改變 block 的位置 並確保其功能和外觀一切正常 成爲可能。
  3. 可複用
    一個界面可以包含同一個 block 的幾個實例。

元素(Element)

大部分組件都不是由多層HTML嵌套組成的,那麼元素就是就是這個組件內部的各級元素。
這裏需要注意的是,不論在HTML中一個塊的結構是什麼,在BEM規則中中,塊下的元素全部屬於塊。

<div class="nav">
    <ul class="list">
        <li class="list-item">列表1 <i class="list-icon"></i> </li>
        <li class="list-item">列表2 <i class="list-icon"></i></li>
        <li class="list-item">列表3 <i class="list-icon"></i></li>
    </ul>
</div>

list-item 和 list-icon 都屬於塊 list 。

修飾符(Modifier)

修飾符與在OOCSS中的皮膚比較類似,屬於組件在不同狀態或組件的不同版本。

其他特點

  • 一個塊必須有一個“名字”(一個CSS類)才能被CSS規則所使用

爲什麼不使用ID選擇器或元素選擇器?

  1. 類允許無限的重複使用,而ID在頁面中只允許使用一次
  2. 元素具有元素本身的意義,不應該和組件互相產生影響
  • 永遠不要鏈式命名
    在之前提到過,元素應該只屬於塊,所以元素的命名只可能是 block--element 而不是 block--element1--element2
  • 儘量避免子代選擇器
  1. 將樣式與HTML結構解耦,減少修改HTML而造成的樣式無法顯示,同樣減少了因HTML修改造成的樣式重寫
  2. 解決了CSS特殊性的問題,所有的樣式都是由一個類選擇器定義。
  3. 但是這很難做到

BEM解決的問題

  • CSS樣式全局性造成的樣式衝突問題
  • 多人協作的命名問題
  • 解決層疊問題,使CSS的優先級保持相對扁平
  • CSS的模塊化,使CSS更具有複用的能力

SMACSS

SMACSS於2011年由JonathanSnook提出,當時他在雅虎工作。

SMACSS是指CSS 的可擴展性和模塊化架構。我們可以將SMACSS看做是對OOCSS和BEM的一個延伸。
剛剛講過了BEM,那麼我們將我們頁面的樣式都化爲了組件,但是在大型網站開發中,這些組件依舊很龐大,那麼在SMACSS中,它提出了將CSS分類這一概念。

SMACSS的分類

在SMACSS中,它認爲CSS應該根據如下五種分組類別進行分類:

  • Base(基礎規範):任何場合下,頁面元素的默認外觀,這裏樣式只會對標籤元素本身做設定,不會出現任何class或id,但是可以有屬性選擇器或是僞類。
  • Layout(佈局規範):佈局是一個網站的基本,無論是左右還是居中,甚至其他什麼佈局,要實現頁面的基本瀏覽功能,佈局必不可少。使用l-/layout-爲前綴。
  • Module(模塊規範):基本思想與BEM類似。使用m-/module-爲前綴。
  • State(狀態規範):元素在特定狀態下的外觀。但是與OOCSS分離Skin的方式不同,SMACSS是抽取更高級別的樣式類,得到更強的複用性。使用is-/has-爲前綴。
  • Theme(主題規範):頁面主題外觀。使用t-/theme-爲前綴

clipboard.png

其他特點

  • 命名方式借鑑BEM命名規範
  • 同樣提倡最小配飾深度,既儘量不使用子選擇器,保持CSS扁平化

Atomic CSS(原子化CSS)

由雅虎公司內部提出,並應用於雅虎官網。

剛剛我們講了幾種方法論,都提到了重用性,那麼原子化CSS就是將重用性運用到了極端。

Atomic Design(原子化思想)

clipboard.png

在2013年網頁設計師Brad Frost從化學中受到啓發:原子(Atoms)結合在一起,形成分子(Molecures),進一步結合形成的生物體(Organisms)。

Brad將這個概念應用在界面設計,我們的界面就是由一些基本的元素組成的。Josh Duck的“HTML元素週期表”(下圖)完美闡述了我們所有的網站、APP、企業內部網、hoobadyboops等等是如何由相同的HTML元素組成的。

  • Atoms(原子):爲網頁構成的基本元素。
  • Molecules(分子):由原子構成的簡單UI組件。
  • Organisms(組織):由原子及分子組成的相對複雜的UI構成物。
  • Templates(模板):將以上元素進行排版,顯示設計的底層內容結構
  • Pages(頁面):將實際內容(圖片、文章等)套件在特定模板,頁面是模板的具體實例。

原子化CSS

理解了原子化的設計,那麼爲什麼說原子化CSS就是將重用性進行到了極端。
讓我們來舉個例子,GitHub上面有一款開源的ACSS工具,叫做 Atomizer
我們使用它來看一下


    <h1>Grid</h1>
    <h2>Inline Block</h2>
    <ul>
        <li class="W(1/2) D(ib) Bgc(#ccc) Ta-c">.W(1/2)</li><!--
        --><li class="W(1/2) D(ib) Bgc(#add8e6)">.W(1/2)</li>
        <li class="W(1/5) D(ib) Bgc(#ccc) Ta-c">.W(1/3)</li><!--
        --><li class="W(1/3) D(ib) Bgc(#add8e6)">.W(1/3)</li><!--
        --><li class="W(1/3) D(ib) Bgc(#add8e6)">.W(1/3)</li>
    <ul>
    <h2>Flex</h2>
    <ul class="D(f)">
        <li class="W(1/2) D(ib) Bgc(#ccc) Ta-c">.W(1/2)</li><!--
        --><li class="W(1/2) D(ib) Bgc(#add8e6)">.W(1/2)</li>
        <li class="W(1/3) D(ib) Bgc(#ccc) Ta-c">.W(1/3)</li><!--
        --><li class="W(1/3) D(ib) Bgc(#add8e6)">.W(1/3)</li><!--
        --><li class="W(1/3) D(ib) Bgc(#add8e6)">.W(1/3)</li>
    <ul>
    <!-- this is just to reload the page if you make any changes to the html -->
    <script src="//localhost:35729/livereload.js"></script>

看到這段代碼,大家肯定會懷疑人生,這是什麼鬼?
那麼我們來下這段HTML生成的css代碼

.Bgc\(\#add8e6\) {
  background-color: #add8e6;
}
.Bgc\(\#ccc\) {
  background-color: #ccc;
}
.Bgc\(\$primary\) {
  background-color: #f3f3f3;
}
.D\(f\) {
  display: flex;
}
.D\(ib\) {
  display: inline-block;
}
.Fw\(b\) {
  font-weight: bold;
}
.Fz\(30px\) {
  font-size: 30px;
}
.W\(1\/2\) {
  width: 50%;
}
.W\(1\/3\) {
  width: 33.3333%;
}
.W\(1\/5\) {
  width: 20%;
}

那麼原子化的CSS到底是什麼?
將CSS的代碼最小化。每一個CSS的類裏面只存在一條屬性,而在使用時,用到這一條屬性時,我們只需要在HTML的class中加入對應的CSS類就可以,最小化了CSS,但是造成了HTML的臃腫。。


總結

我們學習了幾種CSS的方法論,社區內還有很多種其他的方法論,如SUITCSS,ITCSS等等這裏就不一一進行討論了。

最後我們來總結下書寫CSS的方法:

  • CSS模塊化,使CSS與上下文無關
  • 使用 CLASS,確保複用性
  • 使用命名約定及前綴,提高可讀性
  • 不嵌套 CSS,使CSS扁平化
  • 提高CSS的可維護性及擴展性

下一篇我將介紹現在比較流行的編寫CSS的方法如:

  • CSS預處理器
  • CSS後處理器
  • CSS in Js
  • CSS Module

引用

OOCSS——概念篇
BEM的定義
爲什麼我們要用BEM
Atomic Design原子設計理念:構建科學規範的設計系統
什麼是模塊化 CSS?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章