[譯] 探索 SMACSS:可擴充套件的模組化 CSS 框架

Park-ma發表於2019-03-01

當我們在從事大專案或團隊開發工作時,我們經常會發現我們寫的程式碼,凌亂、難以閱讀並且難以擴充套件。尤其是當一段時候後我們回頭再看自己的程式碼,必須回想起當初自己寫的時候的思路才能看懂。

因此,人們建立了許多 CSS 框架來對 CSS 程式碼進行樣式化,使其更具可讀性。比如說,SMACSS,即 Scalable(可擴充套件)Modular Architecture(模組化)CSS,就旨在實現這一點。我採用的是 Johnathan Snook 定的那套 CSS 框架指南。

SMACSS 的架構方法與 Bootstrap 或 Foundation 等 CSS 框架略有不同。相反,它是一組規則,更是一套模板或指南。因此,讓我們來深入探究下這些 CSS 設計模式,看怎麼用它們來讓我們的程式碼更好、更整潔、更易讀、更具模組化。

每個 SMACSS 專案結構分為 5 種規則:

  1. Base(基礎)
  2. Layout(佈局)
  3. Modules(模組)
  4. State(狀態)
  5. Theme(主題)

Base(基礎規則)

在 SMACSS 中,基礎樣式定義了元素全域性的預設樣式。如果你用了樣式重置程式碼,那會讓你的樣式表現在不同瀏覽器上保持一致,即便這些瀏覽器內部定義的預設 CSS 有所不同。

在基礎規則中,你應該只包含基本元素選擇器或者那些偽類選擇器,不應包含類選擇器或者 ID 選擇器。(你應該在理由相當充分時才將類或 ID 放進去,可能也就只有一種情況了:你用了第三方外掛的節點又想對特點節點的預設樣式進行覆蓋。)

這是一個基礎規則的檔案單元的例子:

html {
    margin: 0;
    font-family: sans-serif;
}

a {
    color: #000;
}

button {
    color: #ababab;
    border: 1px solid #f2f2f2;
}
複製程式碼

它應該包含計劃在整個網站上使用的預設的大小、邊距、顏色、邊框和其他預設值。你的排版和表單元素應該在每個頁面上具有統一的樣式,給人感覺它們是統一的設計和主題。

不管你用不用 SMACSS,我都強烈建議避免使用 !important,也不要使用深巢狀,關於為什麼我會在這篇帖子的後面進行深入討論。此外,如果你的專案使用了 CSS 重置程式碼,那你應該把它放在這一部分(我更喜歡使用 Sass,這樣我就可以在 SASS 檔案頂部方便地將重置程式碼引入進來,而不需要將其複製或者在每個頁面的 <header> 元素單獨引用)。

相關資源: Theming with Sass: An SCSS Tutorial

Layout(佈局規則)

佈局將會把頁面分成幾個主要部分 — 不是導航或摺疊皮膚等部分,而是真正的頂級劃分。

Example SMACSS layout styles: header, sidebar, content/main, and footer

SMACSS 佈局規則包括頂部欄、側邊欄、正文、頁尾等主要部分。

這些佈局包括多個 CSS 模組例如 boxes、cards、unordered lists 和 galleries 等,但我會將這些模組放到下一節再詳做討論。讓我們通過一個網頁例子來看看怎麼對頁面進行佈局劃分:

An example web page that can be organized into header, main, and footer layout styles using SMACSS

這些佈局包含一些模組,比如頂部欄的連結和 logo,正文的盒子結構和文章,頁尾的連結和版權。對於上面的佈局,我們通常會設定 ID 選擇器,因為他們在頁面上是單獨唯一的。

你還應該使用字母 l 為佈局規則新增字首,以區分其他的模組樣式。通常你要設定一些和佈局相關的東西,比如邊框,對齊,外邊距等。頁面那些大布局的背景也可以考慮寫進去,即使它看起來不那麼像是一種佈局樣式。

這是一個佈局規則的例子:

#header {  
    background: #fcfcfc;
}

#header .l-right {
    float: right;
}

#header .l-align-center {
    text-align: center;
}
複製程式碼

你也可以將上面這些工具樣式用在對齊上,比方說你想給 header 子節點或節點文字進行對齊定位,那你只需簡單地將合適的類名用在節點上。

另一個例子,你可以在佈局框中使用一些預設的外邊距,例如 .l-margin20px 的頁邊距。然後,無論您想要填充某個 container、element、card 或者 box ,只需將 l-margin 類新增到其中即可。不過你要用一些可複用的寫法:

.l-full-width {
    width: 100%;
}
複製程式碼

不是像這樣內部耦合的東西:

.l-width-25 {
    width: 25px;
}
複製程式碼

我想花點時間談談 SMACSS 中的命名規則。如果您從未在 CSS 中聽說過名稱空間的概念,那它基本上就是將名稱新增到另一個元素的開頭,以幫助區分它與其他任何元素。可我們為什麼要這麼做呢?

我不知道你是否遇到過下面的問題。你寫 CSS 程式碼時發現頁面上有一個標籤,於是你給它加了一些樣式,並命名為 .lable 類。之後你又遇到一個元素,也想將其命名為 .label 類,但樣式與前面的不同。於是兩個不同的東西擁有相同的名稱,這就是一次命名衝突。

名稱空間可幫助你解決此問題。最終,它們在同一級別上被稱為相同的東西,但由於應用了不同的字首,於是屬於不同的名稱空間,也就可以表示兩種不同的樣式

.box--label {
    color: blue;
}

.card--label {
    color: red;
}
複製程式碼

Module(模組規則)

正如我前面提到的,SMACSS 是頁面上可重用的小程式碼塊,是單一佈局的一部分。這部分 CSS 我們想要儲存到單獨的資料夾中,因為我們在一個網頁會有很多這樣的模組程式碼。並且隨著專案的增長,我們可以通過資料夾結構來拆分,比如說,模組/頁面的結構

An example file/folder hierarchy using SMACSS and Sass

於是在前面例子中,假如我們(在頁面上)有一篇文章,它可以作為一個獨立的模組。如何在這裡構建 CSS 呢?我們應該有一個 .article 的類,它有 titletext 的子元素。因此,為了讓它們儲存在同一模組,我們需要在子元素上使用字首:

.article {
    background: #f32;
}

.article--title {
    font-size: 16px;
}

.article--text {
    font-size: 12px;
}
複製程式碼

你一定注意到我們在模組字首後面使用兩個連字元。這是因為有時模組名稱有兩個單詞或者它們的字首類似 big-article。我們需要兩個連字元來描述子元素的位置。比如你可以試著比較 big-article-titlebig-article--titlebig-article--text

此外,如果特定模組佔用了大部分頁面,您可以將模組巢狀在模組中:

<div class="box">
    <div class="box--label">This is box label</div>
    <ul class="box--list list">
        <li class="list--li">Box list element</li>
    </ul>
</div>
複製程式碼

在這個簡單的例子中,你可以看到 box 是一個模組 list 是在它裡面的另一個模組。使用 list--lilist 模組的子項而不是 box 的。這裡的關鍵概念是每個 CSS 規則最多有兩個選擇器,但在大多數情況下只有一個選擇器是帶字首的。

這樣,我們可以避免重複規則,並且在具有相同名稱的子元素上具有額外的選擇器,從而提高速度。它也有助於我們避免使用不需要的 !important 規則,這些規則是結構不合理的 CSS 專案的標誌。

好的例子(注意單選擇器):

.red--box {
    background: #fafcfe;
}

.red-box--list {
    color: #000;
}
複製程式碼

不好的例子(注意選擇器內的重複和重疊):

.red .box {
    background: #fafcfe;
}

.red .box .list {
    color: #000;
}

.box ul {
    color: #fafafa;
}
複製程式碼

State(狀態規則)

在 SMACSS 中狀態規則是描述我們的模組在不同狀態下顯示外觀的一種方式。所以說這一部分是關於互動性的:我們需要有不同的行為去描述元素的隱藏、擴充套件或修改。例如,jQuery 摺疊皮膚控制元件就需要定義狀態,來表示節點內容何時可見何時不可見。它有助於我們在特定時刻定義元素的樣式。

如果狀態規則與佈局規則應用於同一元素上,此時我們要新增額外的規則來覆蓋前面的規則(如果有的話)。狀態規則優先,因為它是規則鏈中的最後一個規則。

與佈局規則一樣,我們建議在狀態規則使用字首。這有助於我們識別它們並給予它們優先權。這裡我們使用 is 字首,如 is-hiddenis-selected

<header id="header">
    <ul class="nav">
        <li class="nav--item is-selected">Contact</li>
        <li class="nav--item">About</li>
    </ul>
</header>
複製程式碼
.nav--item.is-selected {
    color: #fff;
}
複製程式碼

在這裡,!important 是可以使用的,因為狀態規則經常被用於 JavaScript 的修改而不是渲染時。例如,你需要一個元素在網頁載入時是隱藏的,而在點選按鈕時顯示,但是預設類是像下面這樣寫的:

.box .element {
    display: none;
}
複製程式碼

因此如果你只是新增了下面程式碼:

.is-shown {
    display: block;
}
複製程式碼

即使你通過 JavaScript 新增了 .is-shown 之後它還是隱藏的,這是因為第一條規則是是二級深度的,將後一條規則覆蓋。

因此你可以改為這樣定義狀態類:

.is-shown {
    display: block !important;
}
複製程式碼

這就是我們如何區分狀態規則和佈局規則,佈局規則僅用於頁面的初始載入。這樣不僅可以達到目的,還可以保持最少選擇器的優勢。

Theme(主題規則)

這個應該是最顯而易見的規則,因為它定義了顏色、形狀、邊框、陰影還有其他等等。這些大多數都是在網站上重複使用的元素。我們不必在每次使用它們的時候都重新定義它們一下,相反,我們希望定義一個獨特的類然後使用時只需新增上即可。

.button-large {
    width: 60px;
    height: 60px;
}
複製程式碼
<button class="button-large">Like</button>
複製程式碼

不要將 SMACSS 主題規則和基礎規則混淆,基礎規則定義了預設外觀,類似於重置瀏覽器的預設設定,而主題規則定義了一組最終外觀的樣式,唯一的顏色方案。

當網站具有多套樣式或者需要在不同狀態下使用不同主題時,主題規則非常有用,因為當使用者通過頁面上的某些事件例如,主題切換按鈕,觸發時,主題規則可以很方便地更改和切換。至少,他們將所有主題風格儲存在一個地方,以便你可以輕鬆地更改它們並使它們保持良好的組織結構。

CSS 組織方法

我已經介紹了這個 CSS 架構思想的關鍵概念。如果你想了解更多,請訪問 SMACSS 的官方網站並進行深入的學習。

你也可以使用更高階的方法例如 OOCSS 和 BEM。後者幾乎包含了所有前端工作流程和技術。但是一些人會覺得 BEM 的選擇器太長太重,使用起來太複雜。如果你需要更簡單易懂,並容易將其納入你的工作流程 — 以及為你和你的團隊定義基本規則的東西 — SMACSS 非常適合。

這不僅讓團隊新成員很容易的理解以前開發者的工作,還幫助他們快速上手專案,並沒有任何程式碼風格上的差異。 SMACSS 只是一個 CSS 框架,它完成了它所描述的工作,不多也不少。

瞭解基礎知識

CSS 有幾種不同的型別?

有三種不同的型別。內聯 CSS 直接放在 HTML 元素的樣式屬性上。內部 CSS 位於 HTML header 內部 style 標籤內。外部 CSS 是獨立的檔案並通過 HTML 來索引到,避免網站在不同網頁內編寫重複的程式碼。

“CSS 模板”是什麼意思?

CSS 模板通常是用來定義特定的佈局以便我們在不同網頁甚至不同網站上使用它們。但是除了佈局,它們有時也用來為特定元素例如模態框和按鈕甚至它們的組合而定義的一組規則。其他一些則用來定義 HTML 元素的預設樣式。

為什麼 CSS 如此重要?

CSS 在現代網頁中絕對是必須的。沒有它,網頁只是空白頁面上的一堆純文字和圖片。它不僅給網頁提供樣式,還組織布局和提供動畫效果 — 因此它對互交性也很重要。

使用 CSS 有什麼優點?

一個主要的優點是將所有的樣式放在一起而不是讓它們分散在整個網站的每一個元素上。它為我們提供了更多的格式選項,有助於優化頁面載入時間和增加程式碼的複用性。

為什麼可擴充套件性如此重要?

一般來說,隨著專案增長,可擴充套件性帶來的可伸縮性和可維護性非常重要。特別是在CSS中,如果我們編寫的程式碼不具備可擴充套件性和模組化,它會迅速失去控制,變得難以理解和工作,特別是對於新手而言。 因此我們需要 SMACSS。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章