Moving away from Tailwind, and learning to structure my CSS

Julia Evans

告別 Tailwind,學習如何架構我的 CSS

哈囉!8 年前,我興奮地寫下了發現 Tailwind 的心得

那時候我完全不知道該如何架構自己的 CSS 程式碼,在一片混亂和 Tailwind 之間做選擇時,我非常開心地選擇了 Tailwind。它幫我做了好多小網站!

過去一週左右,我把幾個網站從 Tailwind 遷移到更語意化的 HTML 加上原生 CSS,這個過程超級有趣、也超級有意思,所以我想來分享一些學到的東西!

和往常一樣,我不是全職的前端開發者,所以我對 CSS 的學習都是多年來斷斷續續累積而成的。

原來 Tailwind 教會了我很多

當我開始思考如何架構 CSS 時,一開始有點畏縮:我本來就不太擅長組織 CSS!但接著我讀了一些談論如何架構 CSS 的部落格文章(像是A whole cascade of layersHow I write CSS in 2024),然後我意識到幾件事:

  1. 每個 CSS 程式碼庫都有許多不同的面向在同時運作(版面配置!字型!色彩!共用元件!)
  2. 為每一項都建立系統或準則來管理是非常有用的,否則一切很快就會陷入混亂
  3. Tailwind 針對其中一些面向已經有現成的系統,而我已經熟悉那些系統了!或許我可以模仿我喜歡的那些系統!

舉例來說,Tailwind 提供了:

我接下來要談的幾個系統

接下來我會談談我的 CSS 程式碼庫中的幾個面向,以及到目前為止我對每個面向想施加什麼樣的規則。有些是從 Tailwind 借來的,有些則不是。

  1. 重置
  2. 元件
  3. 色彩
  4. 字級大小
  5. 工具類別
  6. 基礎樣式
  7. 間距
  8. 響應式設計
  9. 建置系統

1. 重置

我只是把 Tailwind 的「preflight 樣式」複製過來,方法是打開 tailwind.css 並複製前 200 行左右。

我發現時間久了,我已經和 Tailwind 的 CSS 重置培養出一種默契,舉例來說,Tailwind 會對每個元素設定 box-sizing: border-box(這表示元素的寬度會包含其內距):

* { box-sizing: border-box; }

我想如果要我改成不用這些設定來寫 CSS,會需要一段時間適應,而且我很確定 Tailwind 的重置中還有許多其他細節(像是 html {line-height: 1.5;}),我已經在潛意識中習慣了,甚至沒意識到它們的存在。

2. 元件

接下來的這部分就是 CSS 的主體!

這裡的想法是依照「元件」來組織 CSS,精神上和 Vue 或 React 的元件有點類似。(雖然網站中可能完全沒有 JavaScript)

基本上概念是:

  1. 每個「元件」都有一個獨一無二的 class
  2. 一個元件的 CSS 絕不會覆蓋任何其他元件的 CSS
  3. 每個元件都有自己獨立的 CSS 檔案

所以編輯某個元件的 CSS 時,就不會莫名其妙弄壞另一個元件的東西。而且我實際上想修改的 CSS 中,大概有 80% 都在各個元件檔案裡,所以當我在編輯一個 100 行的元件時,我只需要思考那 100 行就好。對我來說思考起來輕鬆多了。

舉例來說,這段 HTML 可能就是 .zine 這個「元件」。

<figure class="zine horizontal">
    <img src="whatever.jpg">
</figure>

而 CSS 看起來大概像這樣,使用了巢狀選擇器:

.zine {
  ...
  &.horizontal {
    ...
  }
  &.vertical {
    ...
  }
  &:hover {
    ...
  }
}

我還沒有透過任何程式化的方式(像是 Web Components 或@scope)來確保各個元件不會互相干擾,但光是建立一個慣例並盡力遵守,就已經讓我感覺進步很多了。

接下來,要靠一些慣例來維持全站的一致性,並讓這些元件彼此協調!

3. 色彩

colours.css 裡有一堆像這樣的變數,需要時就可以取用。色彩真的很難處理,這次重構我不想重新檢視色彩的使用方式,所以就先維持原樣。

我在這裡試圖遵守的唯一準則,就是網站上使用的所有色彩都要列在這個檔案裡。

:root {
  --pink: #fea0c2;
  --pink-light: #F9B9B9;
  --red: #f91a55;
  --orange: rgb(222, 117, 31);
  ...
}

4. 字級大小

我很欣賞 Tailwind 的一點是,如果我想設定字級大小,只要想著「嗯,我想要文字大一點」,寫下 text-lg 就完成了!如果覺得還不夠大,就改用 xl2xl。完全不用去記到底是用 empx 還是 rem

所以我參考 Tailwind 定義了一堆變數,像這樣:

  --size-xs: 0.75rem;
  --line-height-xs: 1rem;

  --size-sm: 0.875rem;
  --line-height-sm: 1.25rem;

然後如果我想設定字級大小,就可以這樣寫。雖然比 Tailwind 稍微冗長一點,但目前我很滿意。

h3 {
  font-size: var(--size-lg);
  line-height: var(--line-height-lg);
}

5. 工具類別

有些東西像是按鈕,會出現在許多不同的元件中。我把這些稱為「工具類別」。

我從 Tailwind 複製了一些工具類別(像是 .sr-only,用於只應呈現給螢幕報讀器使用者的內容)。

這個區塊非常小,我會盡量小心不要隨意更動這裡的內容。

6. 基礎樣式

「基礎」樣式是指我自己決定要套用到全站的樣式。我必須讓這個區塊保持非常小,因為我還沒有足夠的信心在全站強制套用太多樣式。目前我只對這兩條感到安心,而且我可能會修改 <section> 那一條:

/* put a 950px column in the middle of each <section> */
section {
  --inner-width: 950px;
  padding: 3rem max(1rem, (100% - var(--inner-width))/2);
}

a {
  color: var(--orange);
}

我想對基礎樣式來說,對我最容易的做法是由下而上——先在基礎樣式中幾乎什麼都不放,然後隨著我發現共通的需求,再把一些樣式從元件搬到基礎樣式中。

7. 間距

我還沒有完全想出一套管理內距和外距的方法。不過我確實試圖比以前用 Tailwind 時更有原則——以前我只是隨意地到處加上內距和外距,直到看起來順眼為止。

目前我正努力讓外層的版面配置元件盡可能負責間距的控制。舉例來說,如果我有一個 <section> 裡面有很多子元素,我希望它們之間有間距,可能會用這樣的方式來平均分配間距:

section > *+* {
  margin-top: 1rem;
}

一些啟發我的部落格文章:

8. 響應式設計:多用格線吧!

我以前在 Tailwind 中做響應式設計的方式是用大量的媒體查詢。Tailwind 有一種 md:text-xl 語法,意思是「在 md 或更大的尺寸上套用 text-xl 樣式」。

現在我嘗試一種相當不同的做法,就是做出更具彈性的 CSS 格線版面配置,讓版面不需要那麼多斷點。這很難,但學習格線能做到什麼真的非常有趣,而且這是個我認為用 Tailwind 做不到的好例子。

舉例來說,我一直在學習如何使用 auto-fit 來自動在大螢幕上使用 2 欄、在小螢幕上使用 1 欄,像這樣:

  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
  justify-content: center;

我也大量使用了grid-template-areas,這是一個很棒的功能,我認為用 Tailwind 是無法使用的。

一些靈感來源:

9. 建置系統:esbuild

在開發階段,我不需要建置系統:現在的 CSS 已經同時內建了匯入陳述式,像這樣:

@import "reset.css";
@import "typography.css";
@import "colors.css";

以及內建的巢狀選擇器,像這樣:

.page {
  h2 { ...}
}

如果有需要,我可以用 esbuild 來打包正式環境的 CSS 檔案。指令大概像這樣。

esbuild style.css --bundle --loader:.svg=dataurl  --loader:.woff2=file --outfile=/tmp/out.css

雖然我通常會避免使用 CSS 和 JS 的建置系統,但我不排斥使用 esbuild(我在2021 年在這裡寫過相關文章),因為它是基於網頁標準,而且是一個靜態的 Go 執行檔。

為什麼要從 Tailwind 遷移出來?

有幾個人問我為什麼要從 Tailwind 遷移出來。促成這個決定的幾個因素包括:

  • 自從 2018 年以來,Tailwind 變得越來越依賴建置系統,我想現在要在不使用建置系統的情況下使用較新版本的 Tailwind 幾乎是不可能的(?)。所以這麼多年來我一直使用 Tailwind v2。(據說還有一個 litewind
  • 一直以來,照理說使用 Tailwind 就應該搭配建置系統,但我其實從來沒有那樣做,所以在很多專案裡我都有 2.8MB 的 tailwind.min.css 檔案(gzip 後 270K),感覺有點蠢。
  • 比起剛開始使用 Tailwind 時,我現在的 CSS 能力好多了
  • 最終,Tailwind 是有侷限的:如果你想在 CSS 中做些奇怪的花樣,用 Tailwind 不一定做得到。這些限制可能非常有用(這篇文章的很多內容就是在重新實作 Tailwind 的一些限制!),但在這個階段,我希望能自行選擇要保留哪些限制。
  • 最後我的網站變成在同一個專案中混用了原生 CSS 和 Tailwind,維護起來一點也不好玩
  • 我開始好奇,撰寫更語意化的 HTML 會是什麼感覺。

我感到好奇的 CSS 功能

在做這些事的過程中,我認識了許多我還沒使用過、但很想找機會學習的 CSS 功能:

我離開 Tailwind 的最後一個原因

在這篇文章中,我談了很多從使用 Tailwind 中學到的東西,而那些都是真的。

但我 3 年前讀過一篇名為Tailwind and the Femininity of CSS的文章,讓我印象非常深刻。老實說,我一開始對 CSS 的態度可能就有點像那篇文章所描述的那樣:

他們聽說它很簡單,所以就以為它很容易。但接著當他們嘗試使用時,卻行不通。那一定是語言本身的錯,因為他們知道自己很聰明,而這本來應該是很容易的。

但在過去 10 年裡,我學會了真正喜愛並尊重 CSS 這項技術。

所以多年前我就決定,與其貶低 CSS,不如用「把 CSS 學得更好、認真看待它這項技術」來回應「CSS 很難」這句話。這樣的轉變改變了我的一切:我發現過去讓我感到挫折的許多問題(「置中是不可能的」)其實早就在 CSS 中得到解決,而且我也理解到「置中」的意思並不總是那麼直觀,有很多種做法是很合理的。CSS 很難,是因為它正在解決一個困難的問題!

過去 10 到 15 年間打造的新 CSS 功能(其中一些我在這篇文章中已經談過!)讓我印象深刻,它們讓 CSS 變得更容易使用,而花時間提升自己的 CSS 技能是一段非常棒的體驗。

而那篇文章讓我覺得,Tailwind 助長了對 CSS 專業的貶低,而即使 Tailwind 對我個人來說曾是個有用的工具,我也不想成為其中的一部分。尤其在這個 LLM 的時代,重視人類的專業比以往任何時候都更加重要。

另一篇影響我的、批評 Tailwind 的部落格文章:

目前就分享到這裡!

感謝Melody Starling(梅洛迪·史達林),她最初為 wizardzines.com 設計並撰寫了 CSS,網站上所有酷炫有趣的地方都要歸功於梅洛迪·史達林。

另外,在進行這些工作的期間,我讀了許多關於 CSS 的精彩部落格文章(來自CSS TricksSmashing Magazine等),我已經盡量在文章中附上這些連結,非常感謝 CSS 社群的大家如此樂於分享他們的實務經驗。

原文由 Julia Evans 發布

本文章由 muse-spark-1.2-contributor 進行翻譯