告別 Tailwind,學習如何架構我的 CSS
哈囉!8 年前,我興奮地寫下了發現 Tailwind 的心得。
那時候我完全不知道該如何架構自己的 CSS 程式碼,在一片混亂和 Tailwind 之間做選擇時,我非常開心地選擇了 Tailwind。它幫我做了好多小網站!
過去一週左右,我把幾個網站從 Tailwind 遷移到更語意化的 HTML 加上原生 CSS,這個過程超級有趣、也超級有意思,所以我想來分享一些學到的東西!
和往常一樣,我不是全職的前端開發者,所以我對 CSS 的學習都是多年來斷斷續續累積而成的。
原來 Tailwind 教會了我很多
當我開始思考如何架構 CSS 時,一開始有點畏縮:我本來就不太擅長組織 CSS!但接著我讀了一些談論如何架構 CSS 的部落格文章(像是A whole cascade of layers或How I write CSS in 2024),然後我意識到幾件事:
- 每個 CSS 程式碼庫都有許多不同的面向在同時運作(版面配置!字型!色彩!共用元件!)
- 為每一項都建立系統或準則來管理是非常有用的,否則一切很快就會陷入混亂
- Tailwind 針對其中一些面向已經有現成的系統,而我已經熟悉那些系統了!或許我可以模仿我喜歡的那些系統!
舉例來說,Tailwind 提供了:
我接下來要談的幾個系統
接下來我會談談我的 CSS 程式碼庫中的幾個面向,以及到目前為止我對每個面向想施加什麼樣的規則。有些是從 Tailwind 借來的,有些則不是。
- 重置
- 元件
- 色彩
- 字級大小
- 工具類別
- 基礎樣式
- 間距
- 響應式設計
- 建置系統
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)
基本上概念是:
- 每個「元件」都有一個獨一無二的 class
- 一個元件的 CSS 絕不會覆蓋任何其他元件的 CSS
- 每個元件都有自己獨立的 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 就完成了!如果覺得還不夠大,就改用 xl 或 2xl。完全不用去記到底是用 em、px 還是 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 是無法使用的。
一些靈感來源:
- 來自 CSS Tricks 的不用媒體查詢的響應式格線版面配置
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 功能:
@layer(來自A Whole Cascade of Layers)- @scope(特別是規範中這個如何在「元件」CSS 設計中使用 @scope 的範例!)
- container queries(容器查詢)
- subgrid(子格線)
我離開 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 Tricks、Smashing Magazine等),我已經盡量在文章中附上這些連結,非常感謝 CSS 社群的大家如此樂於分享他們的實務經驗。
隨機一篇部落格