為什么使用Tailwind Css框架?
在還沒(méi)有前端開(kāi)發(fā)這個(gè)概念的時(shí)代,CSS 其實(shí)作為一個(gè)比較簡(jiǎn)單的 DSL 還相對(duì)湊合夠用,但隨著前端項(xiàng)目越來(lái)越復(fù)雜,前端各種開(kāi)發(fā)模式都在隨著項(xiàng)目規(guī)模擴(kuò)大的需求而不斷進(jìn)化,比如前端服務(wù)上我們由服務(wù)端直出變?yōu)楹?jiǎn)單的前后端分離再慢慢的升級(jí)成前后端融合的 serverless,再比如 JS 的寫(xiě)法上我們從開(kāi)始最原始的單文件腳本慢慢引入了各種模塊化的方案再到今天組件化全面開(kāi)花。同樣的進(jìn)化當(dāng)然也會(huì)發(fā)生在 CSS 的開(kāi)發(fā)上。
CSS 作為一個(gè)(曾經(jīng))只有全局作用域的 DSL 其實(shí)從來(lái)都不適合大型工程,畢竟 HTML 被發(fā)明時(shí)只是用來(lái)寫(xiě)文檔,CSS 也只是為了加些簡(jiǎn)單的樣式而不是設(shè)計(jì)用于富應(yīng)用的。但隨著前端項(xiàng)目規(guī)模的擴(kuò)大, CSS 也不得不適應(yīng)這一歷史進(jìn)程。在 node 剛剛被發(fā)明前后那段時(shí)間前端工程化還不是很成熟的階段,工程師們想了各種辦法來(lái)盡量緩和這一矛盾,比如 BEM、OOCSS、SMACSS 等命名方案來(lái)分離關(guān)注點(diǎn),又比如 less、Sass 等工具豐富一下 CSS 的語(yǔ)法并且可以有一個(gè) build 的過(guò)程使 CSS 有了初級(jí)的模塊化能力。但 CSS 不適用于大型工程的問(wèn)題依然嚴(yán)重,F(xiàn)acebook 的開(kāi)發(fā)經(jīng)理(也是 prettier 的作者之一)vjeux 在 2014 年的一次演講[1]中總結(jié)了 CSS 不適用于大型項(xiàng)目的幾個(gè)痛點(diǎn)。

Why CSS modules
CSS modules 就是為了解決上面那些痛點(diǎn)而被發(fā)明的,具體的原理就是通過(guò)編譯生成全局唯一類(lèi)名,從而完全不用類(lèi)名樣式擔(dān)心沖突。它很好的解決了項(xiàng)目規(guī)模增大的問(wèn)題,配合 less 或者 Sass 這種預(yù)處理器也可以實(shí)現(xiàn)相當(dāng)程度的工程化,對(duì)于大部分的場(chǎng)景他已經(jīng)足夠使用。但 CSS modules 也有著他自己的缺點(diǎn):
如果你重度使用了 less 或者 Sass 這種預(yù)處理器,引入了各種變量、mixin、函數(shù)等等特性,會(huì)造成 JS 和 CSS 中工程化生態(tài)的割裂。 不好刪代碼:一來(lái)只要是 CSS 文件就讓人有 copy-paste 的欲望很容易造成代碼的冗余,二來(lái) CSS 文件里的類(lèi)沒(méi)法和外面的 JS 代碼關(guān)聯(lián)起來(lái),需要借助額外的工具才能引入類(lèi)型系統(tǒng)。雖然不一定會(huì)影響最終的代碼體積(PurgeCSS[2]),但對(duì)于工程的可讀性和可維護(hù)性還是有一定污染的。
個(gè)人還有很討厭 CSS modules 的一點(diǎn)就是一旦你用 CSS modules 你就必須得分兩個(gè)文件,對(duì)于可讀性的影響積累下來(lái)其實(shí)非常大,碰到一個(gè)稍微復(fù)雜一點(diǎn)的組件就得左右兩頭來(lái)回改。現(xiàn)代基于組件的 web 開(kāi)發(fā)其實(shí)更適合把模板、邏輯、樣式都盡量放在一起,最好是放在一個(gè)文件[3]里。
Why CSS in JS
其實(shí)相比于 CSS modules,CSS in JS 的方案被 vjeux 提出的時(shí)間要更早,當(dāng)然最開(kāi)始的 CSS in JS 基本上可以理解為單純的把行內(nèi)樣式放到對(duì)象里去,與目前流行的基于 Tagged Templates 的 CSS in JS 方案差別非常大。
得益于組件化理念深入人心,開(kāi)發(fā)者們不再關(guān)心具體的 HTML 和 CSS,復(fù)用組件就是安裝引入 npm 包后直接使用。CSS in JS 的方案可以很好的契合這一開(kāi)發(fā)方式,開(kāi)發(fā)者不需要引入 CSS,不再需額外處理 CSS 的 bundle、prefix,所有都是 JS 也就不再需要配置各種 CSS 預(yù)處理器,極大降低了開(kāi)發(fā)成本。
CSS in JS 其實(shí)是個(gè)挺口水的話題,因?yàn)樵陂_(kāi)發(fā)理念、工程成本、開(kāi)發(fā)場(chǎng)景適配等等方面都有很多可以講的。鑒于本文主要是安利 tailwind 就不展開(kāi)了。目前最流行的 CSS in JS 方案是 styled-components,另外其實(shí)還有個(gè)人認(rèn)為更強(qiáng)大的 emotion 也有不少用戶,都是好東西。
Why Tailwind CSS
https://tailwindcss.com/
Tailwind CSS 其實(shí)就是把在現(xiàn)代工程化框架里把原子 CSS 做到極致的一個(gè) CSS 框架。其實(shí)原子 CSS 很早就出現(xiàn)了,最經(jīng)典的如 clearfix ,在很多早期的 web 項(xiàng)目里都會(huì)有或多或少的原子 CSS。但早期的原子 CSS 并不被認(rèn)為是一種最佳實(shí)踐,或者說(shuō)被認(rèn)為是一種很差的方案。那個(gè)時(shí)代提倡所謂的「關(guān)注點(diǎn)分離」,HTML 的 class 應(yīng)該有自己的語(yǔ)義,不應(yīng)該把樣式或者邏輯附在上面。不過(guò)隨著時(shí)代的發(fā)展,在組件化流行的今天我們其實(shí)已經(jīng)并不怎么關(guān)心 HTML 的語(yǔ)義(甚至那都不是 HTML,叫 JSX),語(yǔ)義化的功能已經(jīng)被組件所取代了。對(duì)于每一個(gè) div 標(biāo)簽,我們關(guān)心的其實(shí)只有他的樣式。在這種背景下原子 CSS 就顯得很有用了。
使用統(tǒng)一的「系統(tǒng)」變量可以極大減小心智負(fù)擔(dān)。
如果我現(xiàn)在需要把這個(gè)按鈕的背景色變成「那個(gè)」藍(lán)色,你該怎么寫(xiě)?
在今天一個(gè)稍微嚴(yán)肅一點(diǎn)的前端項(xiàng)目,都會(huì)有一套所謂的「設(shè)計(jì)語(yǔ)言」(哪怕是直接套用現(xiàn)有的),他會(huì)規(guī)范頁(yè)面中各種元素的「Design Token」,比如藍(lán)色是那個(gè)藍(lán),紅色是哪個(gè)紅,圓角是多少間距是多少。現(xiàn)在比如說(shuō)我需要把需要把這個(gè)按鈕的背景色變成藍(lán)色,你該怎么寫(xiě)?只是為了完成需求那笨辦法有很多無(wú)庸贅述,但我們其實(shí)應(yīng)該把這個(gè)我們所用的設(shè)計(jì)語(yǔ)言的「Design Token」在工程里維護(hù)起來(lái)。tailwind 天然就支持這一點(diǎn)。
// BAD
.button {
background: #3370ff; // 不知道哪里來(lái)的神秘字符串
}
// GOOD
.button {
@apply bg-blue-500; // blue-500 是我們?cè)O(shè)計(jì)語(yǔ)言中規(guī)定的正藍(lán)色
}

再比如我們的項(xiàng)目的 CSS 中經(jīng)常會(huì)有各種神秘?cái)?shù)字,比如 17px、27px、35px 這種,這種 magic number 積累多了以后其實(shí)對(duì)于心智負(fù)擔(dān)相當(dāng)大,因?yàn)槟悴⒉恢涝撨x擇哪個(gè)數(shù)字合適只能看著調(diào)。使用 tailwind 規(guī)定了「Design Token」之后可以很大程度緩解這一點(diǎn)。其實(shí)對(duì)于設(shè)計(jì)師來(lái)說(shuō),基于 4px 的設(shè)計(jì)方案也是一種好的選擇[4]。
// BAD
.sliceContainer {
padding: 24px 24px 13px; // why 13 ?
}
// GOOD
.sliceContainer {
@apply px-6 pt-6 pb-3;
}
使用原子類(lèi)可以大大減少需要起名的場(chǎng)景

命名可以算是開(kāi)發(fā)中最難的事情之一,尤其是在組件化開(kāi)發(fā)已經(jīng)深入人心的今天,你其實(shí)完全沒(méi)必要給你的 div 起一個(gè)有意義的名字。使用這個(gè)組件的頁(yè)面并不會(huì)關(guān)心你組件的頂部叫 header,底部叫 footer(除非你是些基礎(chǔ)組件需要給外界復(fù)用),你只需要把樣式放上去就好了。
你起過(guò)多少 wrapper、container、content、box、section、fragment 這種沒(méi)意義的 className?


同樣一段代碼,不用起名字可以少掉不少頭發(fā)
也許有人會(huì)覺(jué)得大量的內(nèi)聯(lián)樣式類(lèi)很不好維護(hù),不過(guò)就我們實(shí)踐下來(lái)的幾個(gè)大型項(xiàng)目的經(jīng)驗(yàn)來(lái)說(shuō),相比 CSS modules ,行內(nèi)樣式在可維護(hù)性上其實(shí)是要更好一些的。
與組件內(nèi)聯(lián)可以更好的實(shí)現(xiàn)「高內(nèi)聚低耦合」
所有使用 CSS(包括 CSS modules)的解決方案其實(shí)都有一個(gè)問(wèn)題,就是不好刪代碼:你很難確定這段樣式是不是真的沒(méi)用了,直到出線上事故為止。使用 tailwind css 你可以讓樣式到死都跟著組件走,組件刪了樣式也就去掉了,幾乎零成本的降低了冗余代碼的可能性。
Utility-First, not Utility-Only
最后,使用 tailwind 不是一個(gè)必選項(xiàng),他可以很好的和其他方案結(jié)合著使用,用它也幾乎不會(huì)帶來(lái)任何成本。在原子樣式或者說(shuō)「Design Token」上有更為激進(jìn)需求的可以考慮 chakra,幾乎就是 tailwind 的 react/vue 版。
參考閱讀
React: CSS in JS – NationJS[5]
CSS Modules Welcome to the Future[6]
CSS Utility Classes and Separation of Concerns[7]
Why Tailwind CSS[8]
參考資料
演講: https://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html
[2]PurgeCSS: https://purgecss.com/
[3]放在一個(gè)文件: https://vuejs.org/v2/guide/single-file-components.html#What-About-Separation-of-Concerns
[4]好的選擇: https://www.uisdc.com/4px-design
[5]React: CSS in JS – NationJS: https://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html
[6]CSS Modules Welcome to the Future: https://glenmaddern.com/articles/css-modules
[7]CSS Utility Classes and Separation of Concerns: https://adamwathan.me/css-utility-classes-and-separation-of-concerns
[8]Why Tailwind CSS: https://www.swyx.io/why-tailwind
END


“分享、點(diǎn)贊、在看” 支持一波
