做中後台業務,為什麼我不建議你使用 Tailwind CSS?

![1___f27S-qQF2CAASt5bOwqg.png](https://i.imgur.com/dIRz7NB.jpeg)

大家好,我又來了😁

最近我接手了一個隔壁小組轉過來的中後台重構專案。

交接的時候,對方的技術負責人特意跟我強調,說這個專案採用了最新的技術棧,全面擁抱了 Tailwind CSS,開發體驗極其絲滑。

我當時心裡還挺期待,畢竟這兩年 Tailwind 的風刮得太大了,各種國內外大神都在瘋狂帶貨。結果週末我抽空把程式碼拉下來,打開 VSCode 準備梳理一下業務主流程。盯著螢幕不到十分鐘,我覺得自己的眼睛快瞎了。

光說理論沒意思,我直接給你們截取一段真實的、承載了各種表單驗證和狀態聯動的業務側邊欄元件。你們自己品鑑一下所謂的極致開發體驗👇:

<div><div><div></div><span>jsx</span></div><div><div> <span>體驗AI代碼助理</span></div><div> <span>代碼解讀</span></div><div>複製代碼</div></div></div>```
<span><span>const</span> <span>OrderCard</span> = (<span>{ order, isAdmin, isExpanded }</span>) => {</span>
<span>  <span>return</span> (</span>
<span>    <span><span>div</span> </span></span>
<span>      <span>className</span>=<span>{</span>`<span>flex</span> <span>flex-col</span> <span>w-full</span> <span>p-5</span> <span>mb-4</span> <span>border</span> <span>rounded-lg</span> <span>shadow-sm</span> <span>transition-all</span> <span>duration-300</span> ${</span>
<span>        <span>isAdmin</span> ? '<span>bg-red-50</span> <span>border-red-200</span>' <span>:</span> '<span>bg-white</span> <span>border-gray-200</span>'</span>
<span>      } ${</span>
<span>        <span>isExpanded</span> ? '<span>max-h-</span>[<span>800px</span>]' <span>:</span> '<span>max-h-24</span> <span>overflow-hidden</span>'</span>
<span>      } <span>hover:shadow-md</span> <span>cursor-pointer</span>`}</span>
<span>    ></span>
<span>      <span>div</span> <span>className</span>=<span>'flex items-center justify-between pb-3 mb-3 border-b border-gray-100'</span>></span>
<span>        <span>span</span> <span>className</span>=<span>'text-sm font-semibold text-gray-800 truncate w-[60%]'</span>></span>
<span>          {order.id}</span>
<span>        <span><span>span</span>></span></span>
<span>        <span>span</span> </span>
<span>          <span>className</span>=<span>{</span>`<span>px-2</span> <span>py-1</span> <span>text-xs</span> <span>rounded-full</span> ${</span>
<span>            <span>order.status</span> === <span>'PAID'</span> </span>
<span>              ? '<span>bg-green-100</span> <span>text-green-700</span>' </span>
<span>              <span>:</span> '<span>bg-orange-100</span> <span>text-orange-700</span>'</span>
<span>          }`}</span>
<span>        ></span>
<span>          {order.statusText}</span>
<span>        <span><span>span</span>></span></span>
<span>      <span><span>div</span>></span></span>
<span>      {/* 內部極其複雜的業務欄位渲染... */}</span>
<span>    <span><span>div</span>></span></span>
<span>  );</span>
<span>}</span>

程式碼能跑嗎?當然能跑。UI 還原度高嗎?也挺高。但作為接下來要維護這個專案的組長,我只覺得一陣頭皮發麻。

許多前端新人,甚至是習慣做 C 端 獨立開發的朋友,對 `Tailwind` 簡直是頂禮膜拜。因為它不用命名,不用在 `JS` 和 `CSS` 檔案之間來回切換,寫起來確實有快感。

但作為走過無數中後台專案的資深開發,我今天必須給這股跟風熱潮潑一盆冷水: 在絕大多數重型中後台業務場景裡,`Tailwind CSS` 並不什麼神兵利器,反而會為後期維護帶來不便。

來,咱們拿真實程式碼說話,看看它到底是怎麼摧毀中後台工程的👇。

---

### 徹底掩蓋你的業務主線?

做中後台系統,最難的從來不是畫 UI,而是處理極度複雜的資料狀態流轉。

上面那段程式碼最大的问题在於訊號雜訊比極低。作為一個接手程式碼的前端,我點開這個檔案,首先想看的是:這個元件在不同權限、不同展開狀態下,業務邏輯是怎麼走的?

但在 `Tailwind` 的體系下,我的視線全被 `flex`、`p-5`、`mb-4`、`max-h-[800px]` 這種毫無業務價值的視覺原子類給強暴了。如果退回到傳統的 `CSS Modules` 方案,這段程式碼在 `JS` 側應該長什麼樣?咱們對比一下:

<div><div><div></div><span>jsx</span></div><div><div> <span>體驗AI代碼助理</span></div><div> <span>代碼解讀</span></div><div>複製代碼</div></div></div>```
<span><span>import</span> classNames <span>from</span> <span>'classnames'</span>;</span>
<span><span>import</span> styles <span>from</span> <span>'./OrderCard.module.less'</span>;</span>
<span></span>
<span><span>const</span> <span>OrderCard</span> = (<span>{ order, isAdmin, isExpanded }</span>) => {</span>
<span> <span>return</span> (</span>
<span> <span><span>div</span> </span></span>
<span> <span>className</span>=<span>{classNames(styles.orderCard,</span> {[<span>styles.adminMode</span>]<span>:</span> <span>isAdmin</span>,</span>
<span> [<span>styles.expanded</span>]<span>:</span> <span>isExpanded</span></span>
<span> })}</span>
<span> ></span>
<span> <span>div</span> <span>className</span>=<span>{styles.cardHeader}</span>></span>
<span> <span>span</span> <span>className</span>=<span>{styles.orderId}</span>></span>{order.id}<span><span>span</span>></span>
<span> <span>span</span> </span>
<span> <span>className</span>=<span>{classNames(styles.statusBadge,</span> {</span>
<span> [<span>styles.statusPaid</span>]<span>:</span> <span>order.status</span> === <span>'PAID'</span>,</span>
<span> [<span>styles.statusPending</span>]<span>:</span> <span>order.status</span> === <span>'PENDING'</span></span>
<span> })}</span>
<span> ></span>
<span> {order.statusText}</span>
<span> <span><span>span</span>></span></span>
<span> <span><span>div</span>></span></span>
<span> {/ 業務欄位一目了然 /}</span>
<span> <span><span>div</span>></span></span>
<span> );</span>
<span>}</span>

發現差別了嗎?重構後的 JSX 變得極其純粹。我只透過 adminModeexpanded 這種類名,就非常清晰地傳達了業務語意。至於那個訂單編號到底佔百分之幾的寬度,那是 UI 層該關心的事情,它安靜地待在 .less 檔案裡,絕不會來污染我的業務主邏輯。


跟現成的元件庫水土不服

中後台業務不可能脫離 Ant Design、Element Plus 這類重型元件庫。而元件庫的本質,是封裝好了一整套內部的 DOM 結構和 className 規範。

這就帶來了一個極其致命的衝突:當你用 Tailwind 去覆蓋 Ant Design 的內部樣式時,你會寫出極其噁心的 Hack 代碼😖。

比如產品經理要求:在這個特定頁面裡,把 Ant Design 表格的表頭背景色改成淺藍色,欄位的 padding 改小一點。

正常用 Less 的做法是用樣式穿透,精準打擊:

<div><div><div></div><span>less</span></div><div><div> <span>體驗AI代碼助理</span></div><div> <span>代碼解讀</span></div><div>複製代碼</div></div></div>```
<span><span>/* 樣式檔覆蓋 */</span></span>
<span><span>.myCustomTable</span> {</span>
<span>  :<span>deep</span>(.ant-table-thead > tr > th) {</span>
<span>    <span>background-color</span>: <span>#f0f8ff</span>;</span>
<span>    <span>padding</span>: <span>8px</span> <span>16px</span>;</span>
<span>  }</span>
<span>}</span>

你知道那個擁抱 `Tailwind` 的小夥子是怎麼寫的嗎?為了不寫 `CSS` 檔,他強行使用了 `Tailwind v3+` 的任意變體語法:

<div><div><div></div><span>jsx</span></div><div><div> <span>體驗AI代碼助理</span></div><div> <span>代碼解讀</span></div><div>複製代碼</div></div></div>```
<span><span>// Tailwind 強行覆蓋元件庫內部樣式</span></span>
<span>Table</span>
<span> className=<span>'[&.ant-table-thead>tr>th]:bg-blue-50[&.ant-table-thead>tr>th]:py-2 [&.ant-table-thead>tr>th]:px-4 [&.ant-table-tbody>tr>td]:text-gray-600[&_.ant-table-tbody>tr>td]:py-2'</span> </span>
<span> dataSource={data} </span>
<span> columns={columns} </span>
<span>/></span>

這段程式碼合進主分支的時候,我都替後續維護的同事感到悲哀😢。

這玩意兒連換行都沒有,密密麻麻擠在一起。未來如果要做主題切換,或者升級 Ant Design 導致內部 className 變了,誰敢去動這坨連正則都極難匹配的字串?

不僅沒有提高開發效率,反而為了強行湊 Tailwind 的語法,寫出了一堆極難維護的程式碼。


負邊距引發的問題

一行程式碼被寫出來的成本,遠遠低於它在未來三年裡被維護的成本。

Tailwind 本質上就是披著 className 外衣的內聯樣式。它把所有的樣式固化在了 HTML 結構上。

設想真實的維護場景,前任開發為了讓一個按鈕和旁邊的輸入框對齊,極其隨意地寫了一個向左偏移的負間距類名:

<div><div><div></div><span>jsx</span></div><div><div> <span>體驗AI代碼助理</span></div><div> <span>代碼解讀</span></div><div>複製代碼</div></div></div>```
<span>Button</span> className=<span>'-ml-2 mt-1'</span>>提交<span>Button</span>>


半年後你接手這個需求,產品要求在這兩個元素中間加一個 Icon。你看著這個 `-ml-2` 和 `mt-1` 會陷入極其痛苦的掙扎:他當時為什麼要寫負邊距?是因為外層父元素加了錯的 padding 導致的?還是為了抵消 Button 內部自帶的 margin?🤷‍♂️

在傳統 CSS 中,我們往往會留有註解說明為何要抵消輸入框自帶的右側留白。但在 `Tailwind` 裡,沒有註解的容身之所。

為了保證不出線上 Bug,你絕對不敢刪掉那個 `-ml-2`。你會選擇在它後面再打個補丁,加個 `pl-4` 試圖把它頂回來。第二年,另一個接手的同事遇到錯位,又在後面補了個 `mt-[-5px]`🤣🤣🤣。

日積月累,HTML 標籤上的類名越來越長,死碼和衝突碼全堆在 DOM 上,最終變成一座沒人敢碰的屎山💩。

---

### 別瞎搞,先認清你的場景🫡

說了這麼多,難道 `Tailwind` 真的是垃圾嗎?當然絕對不是。

如果你在做偏 C 端 的炫酷落地頁、做 SaaS 官網,或者你是獨立開發者,沒有沉重的歷史包袱,不需要配合複雜的重型元件庫,那 `Tailwind` 絕對是神作。它自帶極其優秀的設計規範,能讓你快速堆出好看的介面。

但我們討論的是中後台。中後台是幹嘛的?團隊十幾個人來回交接,動輒幾百個頁面,充斥著極其複雜的表單聯動和權限校驗,生命週期長達五年甚至十年。

在這種重型專案中,保持業務邏輯的純粹性、分離關注點,遠比你少寫幾行 CSS 重要一萬倍。

好了,今天分享到這,謝謝大家😁

![謝謝大家.gif](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2f8bad954e894b9dba9605268ba35ac3~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&x-expires=1776738808&x-signature=oWNwjng5pZihj%2B5jQcWnulTnATQ%3D)

---

原文出處:https://juejin.cn/post/7628114662257901577

精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝4   💬5   ❤️2
347
🥈
我愛JS
📝1   💬4   ❤️2
114
🥉
Gigi
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登