遠離 Tailwind,學習如何組織我的 CSS
原文由 Julia Evans 于 發布,訂閱此部落格
哈囉!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 styles」,做法是打開 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. 基礎樣式
「基礎」樣式是我自己挑選、套用到整個網站的樣式。我必須讓這個區塊保持非常小,因為我還沒自信到能強制在全站套用很多樣式。目前我只對這兩個覺得還 OK,而且 <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. 響應式設計:多用 grid!
我以前在 Tailwind 裡做響應式設計的方式是用很多 media query。Tailwind 有這種 md:text-xl 語法,意思是「在 md 或更大的尺寸上套用 text-xl 樣式」。
現在我嘗試了相當不同的方法,就是做出更靈活、不需要那麼多斷點的 CSS grid 版面配置。這很難,但學習 grid 能做到什麼真的很有趣,而且這正是個我覺得用 Tailwind 做不到的好例子。
舉例來說,我最近在學怎麼用 auto-fit 來自動在大螢幕上用兩欄、小螢幕上用一欄,像這樣:
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
justify-content: center;我也大量使用了grid-template-areas,這是一個超棒的功能,我覺得用 Tailwind 應該是沒辦法用的。
一些靈感來源:
- A responsive grid layout with no media queries 來自 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 遷移出來。幾個促使我這麼做的原因包括:
- Tailwind 從 2018 年以來變得越來越依賴建置系統,我覺得現在不用建置系統,好像不可能(?)使用新版的 Tailwind。所以我這些年來一直都還在用 Tailwind v2。(聽說還有litewind)
- 本來就一直都是建議搭配建置系統使用 Tailwind,但我從來沒有真的那麼做,所以在很多專案裡我都有 2.8MB 的
tailwind.min.css檔案(gzip 後 270K),感覺有點蠢。 - 我現在的 CSS 能力比剛開始用 Tailwind 時好多了
- 說到底 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,網站上所有酷炫有趣的地方都要歸功於 Melody。
另外,在進行這次遷移的過程中,我讀了好多超棒的 CSS 部落格文章(來自CSS Tricks、Smashing Magazine 等等),我在文章中試著附上了其中一些連結,也非常感謝 CSS 社群的朋友們如此慷慨地分享他們的實務經驗。
隨機一篇部落格
留言
登入後參與討論