在前面幾天,我們主要使用了手動撰寫的Tailwind色碼(bg-slate-900、text-slate-100)。雖然畫面質感不錯,但如果每次都要在每個元件裡寫死特定的顏色,專案將面臨兩個致命問題:
維護成本極高:如果有一天想將主色調從Slate深藍改為Zinc深灰,必須逐個元件修改。
無法優雅支援Dark/LightMode:寫死的色碼無法跟隨系統主題切換。
今天,我們將引導AI進行設計系統層級的重構:抽取DesignTokens(設計標籤)、管理CSS變數,並透過next-themes實作一鍵無縫切換深色/淺色模式。
1.Vibe重構思維:從具體色碼到語義化標籤(SemanticTokens)
重構的核心心法,是將寫死的值(HardcodedValues)轉換為語義化變數(SemanticVariables):
重構前 (Hardcoded Class):
className="bg-slate-900 border-slate-800 text-slate-100"
重構後 (Semantic Class):
className="bg-background border-border text-foreground"
透過這種轉換,Tailwind CSS類別代表的是語意功能(背景色、邊框色、前景色),而具體的RGB/HSL色值則交給根目錄的CSS變數處理。當主題改變時,元件的CSS Class完全不需要動!
2.實戰步驟 1:建立與更新全域CSS變數(globals.css)
開啟 Cursor,對著 @app/globals.css 發送以下 Prompt:
@app/globals.css(請參考現有CSS)
請幫我重構`globals.css`,採用TailwindCSS+HSL變數結構,支援Light(淺色)與Dark(深色)兩套DesignTokens。
##需求細節:
1.變數定義(HSL格式):
-`--background`/`--foreground`(頁面背景與主要文字)
-`--card`/`--card-foreground`(卡片背景與內容)
-`--primary`/`--primary-foreground`(主視覺品牌色,預設為Indigo/Blue)
-`--muted`/`--muted-foreground`(次要/灰階元素)
-`--border`(分隔線與邊框)
2.`:root`(LightMode):背景為純白/淺灰(`hsl(00%100%)`),文字為深灰/黑。
3.`.dark`(DarkMode):背景為深藍黑(`hsl(222.284%4.9%)`),文字為淺灰/純白。
4.Tailwind設定連結:確保CSS語法支援`@layerbase`綁定,讓`bg-background`與`text-foreground`自動套用全局字體與轉場動畫(`transition-colors`)。
3.實戰步驟2:引入next-themes主題管理器
為了讓主題切換不產生頁面閃爍(Flicker),我們使用業界標竿套件next-themes。
步驟A:安裝套件
在Terminal執行:
npm install next-themes
步驟B:請AI建立ThemeProvider與切換按鈕
發送Prompt對著@components/ThemeProvider.tsx與@components/ThemeToggle.tsx:
請幫我建立兩個元件:
1.`components/ThemeProvider.tsx`:
-包覆`next-themes`的`ThemeProvider`,支援`attribute="class"`與`defaultTheme="system"`。
-需加入`useMounted`避免SSRhydrationmismatch問題。
2.`components/ThemeToggle.tsx`:
-使用ShadcnUI的`Button`與LucideIcons(`Sun`,`Moon`)。
-點擊時切換`theme`(light<->dark)。
-加入流暢的切換動畫與無障礙aria-label。
AI產出的ThemeToggle.tsx:
'use client';
import * as React from 'react';
import { Moon, Sun } from 'lucide-react';
import { useTheme } from 'next-themes';
import { Button } from '@/components/ui/button';
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = React.useState(false);
// 防止 SSR Hydration 不匹配
React.useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return <div className="w-9 h-9" />;
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
className="rounded-lg border border-border bg-background hover:bg-muted text-foreground transition-all"
aria-label="切換深淺色主題"
>
{theme === 'dark' ? (
<Sun className="h-4 w-4 text-amber-400 transition-transform rotate-0 scale-100" />
) : (
<Moon className="h-4 w-4 text-slate-700 transition-transform rotate-0 scale-100" />
)}
</Button>
);
}
4.實戰步驟3:指引AI批量重構元件為語義化Class
現在,我們可以請AI將前幾天產出的DashboardOverview.tsx與MetricCard一次性重構為語義化類別!
重構Prompt:@components/DashboardOverview.tsx請幫我重構這個檔案中的樣式。將所有寫死的bg-slate-900、border-slate-800與text-slate-100替換為Tailwind的語義化CSS變數類別(例如:bg-card、border-border、text-card-foreground、text-muted-foreground),確保在LightMode與DarkMode下都能完美呈現。
今天我們完成了專案架構中非常重要的一步,設計標籤(DesignTokens)與主題系統的解耦:
確立了語義化CSS變數體系,提升代碼可維護性。
成功整合next-themes,讓VibePulse具備無縫切換深淺色模式的能力。
證明了透過AI,全域CSS樣式重構可以在幾分鐘內無痛完成!