組織你的 CSS

當你開始處理更大的樣式表和大型專案時,你會發現維護一個龐大的 CSS 檔案可能具有挑戰性。在本文中,我們將簡要介紹一些編寫易於維護的 CSS 的最佳實踐,以及你在他人使用中會發現的一些解決方案,以幫助提高可維護性。

預備知識 已安裝基本軟體,瞭解 檔案操作 的基本知識,HTML 基礎知識(學習 HTML 簡介),以及 CSS 工作原理的概念(學習 CSS 樣式基礎)。
目標 學習一些整理樣式表的技巧和最佳實踐,並瞭解一些常用的命名約定和工具,以幫助進行 CSS 組織和團隊協作。

保持 CSS 整潔的技巧

以下是一些關於如何保持樣式表組織有序和整潔的一般性建議。

你的專案有編碼風格指南嗎?

如果你正在團隊中處理一個現有專案,首先要檢查的是專案是否有現有的 CSS 樣式指南。團隊樣式指南應始終優先於你自己的個人偏好。通常沒有絕對正確或錯誤的做法,但保持一致性很重要。

例如,請檢視 MDN 程式碼示例的 CSS 指南

保持一致

如果你為專案設定規則,或者獨自工作,那麼最重要的事情就是保持一致。一致性可以透過各種方式實現,例如對類使用相同的命名約定,選擇一種描述顏色的方法,或者保持一致的格式。(例如,你將使用製表符還是空格來縮排程式碼?如果是空格,用多少個空格?)

擁有一套始終遵循的規則可以減少編寫 CSS 時所需的腦力開銷,因為有些決定已經做出。

格式化可讀的 CSS

你會看到 CSS 有幾種格式化方式。一些開發者將所有規則放在一行,如下所示:

css
.box {background-color: #567895; }
h2 {background-color: black; color: white; }

其他開發者則喜歡將所有內容分行

css
.box {
  background-color: #567895;
}

h2 {
  background-color: black;
  color: white;
}

CSS 不介意你使用哪種方式。我們個人認為將每個屬性和值對放在新行上更具可讀性。

註釋你的 CSS

為你的 CSS 添加註釋將幫助任何未來的開發者使用你的 CSS 檔案,但在你休息一段時間後回到專案時,也會對你有所幫助。

css
/* This is a CSS comment
It can be broken onto multiple lines. */

一個好建議是在樣式表中的邏輯部分之間新增一塊註釋,以便在掃描時快速定位不同部分,甚至為你提供一些可以搜尋的內容,以便直接跳轉到 CSS 的該部分。如果你使用一個不會出現在程式碼中的字串,你可以透過搜尋它在各個部分之間跳轉——下面我們使用了 ||

css
/* || General styles */

/* … */

/* || Typography */

/* … */

/* || Header and Main Navigation */

/* … */

你不需要註釋 CSS 中的每一個細節,因為大部分內容都是不言自明的。你應該註釋的是那些你出於某種原因做出特定決定的地方。

例如,你可能以特定方式使用了 CSS 屬性來解決舊瀏覽器的相容性問題

css
.box {
  background-color: red; /* fallback for older browsers that don't support gradients */
  background-image: linear-gradient(to right, red, #aa0000);
}

也許你為了實現某個功能而遵循了一個教程,而 CSS 本身並不是很直觀或容易理解。在這種情況下,你可以將教程的 URL 新增到註釋中。當你一年左右後回到這個專案時,你會感謝自己,那時你可能模糊地記得有一個關於那個東西的很棒的教程,但卻想不起它是從哪裡來的。

在你的樣式表中建立邏輯分割槽

一個好主意是首先在樣式表中放置所有通用樣式。這意味著所有通常會應用的樣式,除非你對該元素做了一些特殊處理。你通常會為以下內容設定規則:

  • body
  • p
  • h1, h2, h3, h4, h5
  • ulol
  • table 屬性
  • 連結

在樣式表的這一部分,我們為網站上的字型提供預設樣式,為資料表和列表等設定預設樣式。

css
/* || GENERAL STYLES */

body {
  /* … */
}

h1,
h2,
h3,
h4 {
  /* … */
}

ul {
  /* … */
}

blockquote {
  /* … */
}

本節之後,我們可以定義一些實用類,例如,一個用於移除我們要以 flex 項或以其他方式顯示的列表的預設列表樣式的類。如果你有一些樣式選擇,你知道你想要應用於許多不同元素,它們可以放在此節中。

css
/* || UTILITIES */

.no-bullets {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* … */

然後我們可以新增網站範圍內使用的所有內容。這可能包括基本的頁面佈局、頁首、導航樣式等。

css
/* SITEWIDE */

.main-nav {
  /* … */
}

.logo {
  /* … */
}

最後,我們將包含特定內容的 CSS,按它們使用的上下文、頁面甚至元件進行分類。

css
/* || STORE PAGES */

.product-listing {
  /* … */
}

.product-box {
  /* … */
}

透過這種方式組織,我們至少知道在樣式表的哪個部分尋找我們想要更改的內容。

避免過度特定的選擇器

如果你建立了非常具體的選擇器,你通常會發現需要重複你的 CSS 片段,以便將相同的規則應用於另一個元素。例如,你可能有一個如下所示的選擇器,它將規則應用於在具有 main 類的 <article> 中,具有 box 類的 <p>

css
article.main p.box {
  border: 1px solid #cccccc;
}

如果你想將相同的規則應用於 main 之外的某個元素,或者除了 <p> 之外的某個元素,你將不得不為這些規則新增另一個選擇器,或者建立一個全新的規則集。相反,你可以使用選擇器 .box 將你的規則應用於任何具有 box 類的元素。

css
.box {
  border: 1px solid #cccccc;
}

有時,使內容更具體是有意義的;然而,這通常是例外而不是常規做法。

將大型樣式表拆分成多個較小的樣式表

如果網站的不同部分有非常不同的樣式,你可能希望有一個包含所有全域性規則的樣式表,以及一些包含這些部分所需特定規則的較小樣式表。你可以從一個頁面連結到多個樣式表,並應用正常的層疊規則,其中連結在後的樣式表中的規則會覆蓋連結在前的樣式表中的規則。

例如,我們可能有一個作為網站一部分的線上商店,其中大量 CSS 僅用於樣式化產品列表和商店所需的表單。將這些內容放在不同的樣式表中,並且僅在商店頁面上鍊接,將是合理的。

這可以讓你更容易地組織 CSS,也意味著如果有多人同時處理 CSS,你將減少兩個人同時處理同一個樣式表的情況,從而減少原始碼控制中的衝突。

其他有用的工具

CSS 本身並沒有太多內建的組織方式;因此,你的 CSS 的一致性水平很大程度上取決於你。Web 社群已經開發了各種工具和方法,可以幫助你管理大型 CSS 專案。由於你很可能在與他人合作時遇到這些輔助工具,並且它們通常在一般情況下都有幫助,我們在此簡要介紹了其中一些。

CSS 方法論

你無需為編寫 CSS 設計自己的規則,而是可以從採納社群已經設計並在許多專案中測試過的方法中受益。這些方法本質上是 CSS 編碼指南,它們採用非常結構化的方法來編寫和組織 CSS。通常,它們會使 CSS 比你為該專案編寫和最佳化每個選擇器而定製的規則集更加冗長。

然而,透過採用其中一種方法,你確實獲得了大量的結構。由於這些系統中的許多都得到廣泛使用,其他開發者更有可能理解你所使用的方法,並能夠以相同的方式編寫自己的 CSS,而無需從頭開始摸索你自己的個人方法論。

OOCSS

你遇到的大多數方法都受到面向物件 CSS (OOCSS) 概念的影響,這種方法因 Nicole Sullivan 的工作而流行。OOCSS 的基本思想是將你的 CSS 分解成可重用的物件,這些物件可以在你網站上的任何地方使用。OOCSS 的標準示例是描述為 媒體物件 的模式。這是一種模式,一側是固定大小的影像、影片或其他元素,另一側是靈活內容。我們網站上的評論、列表等隨處可見這種模式。

如果你不採用 OOCSS 方法,你可能會為使用此模式的不同位置建立自定義 CSS,例如,透過建立兩個類,一個名為 comment,包含元件部分的許多規則,另一個名為 list-item,包含與 comment 類幾乎相同的規則,除了微小的差異。這兩個元件之間的差異是 list-item 有一個下邊框,而評論中的影像有邊框,但 list-item 影像沒有。

css
.comment {
  display: grid;
  grid-template-columns: 1fr 3fr;
}

.comment img {
  border: 1px solid grey;
}

.comment .content {
  font-size: 0.8rem;
}

.list-item {
  display: grid;
  grid-template-columns: 1fr 3fr;
  border-bottom: 1px solid grey;
}

.list-item .content {
  font-size: 0.8rem;
}

在 OOCSS 中,你會建立一個名為 media 的模式,它將包含兩種模式的所有通用 CSS——一個基本類,用於大致呈媒體物件形狀的事物。然後我們會新增一個額外的類來處理那些微小的差異,從而以特定的方式擴充套件該樣式。

css
.media {
  display: grid;
  grid-template-columns: 1fr 3fr;
}

.media .content {
  font-size: 0.8rem;
}

.comment img {
  border: 1px solid grey;
}

.list-item {
  border-bottom: 1px solid grey;
}

在你的 HTML 中,評論需要同時應用 mediacomment

html
<div class="media comment">
  <img src="" alt="" />
  <div class="content"></div>
</div>

列表項將應用 medialist-item

html
<ul>
  <li class="media list-item">
    <img src="" alt="" />
    <div class="content"></div>
  </li>
</ul>

Nicole Sullivan 在描述和推廣這種方法方面所做的工作意味著,即使是那些今天不嚴格遵循 OOCSS 方法的人,通常也會以這種方式重用 CSS——它已經作為一種通用的良好方法進入我們的理解。

BEM

BEM 代表塊(Block)、元素(Element)和修飾符(Modifier)。在 BEM 中,塊是一個獨立的實體,例如按鈕、選單或徽標。元素是類似於列表項或標題之類的東西,它與其所在的塊相關聯。修飾符是塊或元素上的一個標誌,用於改變樣式或行為。由於 CSS 類中大量使用了破折號和下劃線,你將能夠識別使用 BEM 的程式碼。例如,請看來自關於 BEM 命名約定 頁面的此 HTML 中應用的類

html
<form class="form form--theme-xmas form--simple">
  <label class="label form__label" for="inputId"></label>
  <input class="form__input" type="text" id="inputId" />

  <input
    class="form__submit form__submit--disabled"
    type="submit"
    value="Submit" />
</form>

附加的類與 OOCSS 示例中使用的類相似;但是,它們使用了 BEM 嚴格的命名約定。

BEM 在大型 Web 專案中廣泛使用,許多人以這種方式編寫他們的 CSS。你很可能會遇到使用 BEM 語法的示例,即使在教程中,也沒有提及 CSS 為何以這種方式構建。

在 CSS Tricks 上閱讀更多關於此係統 BEM 101

其他常見系統

有大量這類系統正在使用中。其他流行的方法包括由 Jonathan Snook 建立的 可擴充套件和模組化 CSS 架構 (SMACSS)、來自 Harry Roberts 的 ITCSS,以及最初由 Yahoo! 建立的 Atomizer CSS (ACSS)。如果你遇到一個使用這些方法之一的專案,那麼優點是你將能夠搜尋並找到許多文章和指南來幫助你理解如何以相同的風格編寫程式碼。

使用這類系統的缺點是,它們可能看起來過於複雜,尤其是對於較小的專案。

CSS 的構建系統

另一種組織 CSS 的方法是利用前端開發者可用的一些工具,這些工具允許你採用稍微更具程式設計性的方法來編寫 CSS。有許多工具,我們稱之為預處理器後處理器。預處理器處理你的原始檔案並將它們轉換為樣式表,而後處理器則處理你完成的樣式表並對其進行一些操作——也許是為了最佳化它以便更快地載入。

使用這些工具中的任何一個都需要你的開發環境能夠執行進行預處理和後處理的指令碼。許多程式碼編輯器可以為你完成這項工作,或者你可以安裝命令列工具來幫助。

最受歡迎的預處理器是 Sass。這不是一個 Sass 教程,所以我將簡要解釋一些 Sass 可以做的事情,即使你不使用其他 Sass 功能,這些功能在組織方面也非常有幫助。如果你想了解更多關於 Sass 的知識,可以從 Sass 基礎 文章開始,然後繼續閱讀他們的其他文件。

定義變數

CSS 現在有了原生的 自定義屬性,這使得這個功能的重要性越來越低。然而,你可能使用 Sass 的一個原因是能夠將專案中使用的所有顏色和字型定義為設定,然後將該變數用於整個專案。這意味著如果你發現使用了錯誤的藍色陰影,你只需要在一個地方更改它。

如果像下面第一行那樣建立了一個名為 $base-color 的變數,那麼就可以在樣式表中任何需要該顏色的地方使用它。

scss
$base-color: #c6538c;

.alert {
  border: 1px solid $base-color;
}

一旦編譯成 CSS,你最終會在最終的樣式表中得到以下 CSS。

css
.alert {
  border: 1px solid #c6538c;
}

編譯元件樣式表

我上面提到過,組織 CSS 的一種方法是將樣式表分解成更小的樣式表。當使用 Sass 時,你可以將這一點提升到另一個層次,擁有許多非常小的樣式表——甚至可以為每個元件都有一個單獨的樣式表。透過使用 Sass 中包含的功能(區域性檔案),它們都可以編譯成一個或少量樣式表,以實際連結到你的網站。

因此,例如,使用 partials,你可以在一個目錄中擁有多個樣式檔案,例如 foundation/_code.scssfoundation/_lists.scssfoundation/_footer.scssfoundation/_links.scss 等。然後你可以使用 Sass 的 @use 規則將它們載入到其他樣式表中

scss
// foundation/_index.scss
@use "code";
@use "lists";
@use "footer";
@use "links";

如果所有區域性檔案都載入到一個索引檔案中,如上所示,那麼你可以一次性將整個目錄載入到另一個樣式表中。

scss
// style.scss
@use "foundation";

注意:嘗試 Sass 的一個簡單方法是使用 CodePen — 你可以在 Pen 的設定中為 CSS 啟用 Sass,然後 CodePen 將為你執行 Sass 解析器,以便你看到應用了常規 CSS 的結果網頁。有時你會發現在他們的 CodePen 演示中,CSS 教程使用了 Sass 而不是純 CSS,所以瞭解一些 Sass 知識會很方便。

用於最佳化的後處理

如果你擔心增加樣式表的大小,例如,透過新增大量額外的註釋和空白,那麼後處理步驟可以是最佳化 CSS,方法是剝離生產版本中所有不必要的內容。一個實現此功能的後處理器解決方案的例子是 cssnano