【Tailwind CSS 教學】#04 客製化配置與最佳實踐

Tailwind CSS 客製化配置與最佳實踐 – 基礎測驗

測試你對 Tailwind 配置和最佳實踐的理解

1 在 Tailwind v3 的 tailwind.config.js 中,如果想要新增自訂顏色但保留所有預設顏色,應該把設定放在哪裡?
2 在 Tailwind v4 中,客製化設計系統主要使用哪個 CSS 指令?
3 關於 @apply 指令,以下哪個是推薦的使用情境?
4 使用 @tailwindcss/typography 插件時,要讓內容套用排版樣式,需要加上哪個 class?
5 以下程式碼為什麼會導致樣式無法正常顯示?
const color = 'red'; <div className={`bg-${color}-500`} />
0/5
繼續加油!

當你開始在真實專案中使用 Tailwind CSS 時,很快就會遇到「預設的設計系統不完全符合需求」的情況。這時候,你需要知道如何客製化 Tailwind 的配置。本篇將帶你了解配置檔案的架構、如何自訂設計系統,以及撰寫 Tailwind CSS 專案的最佳實踐。

配置檔案:v3 vs v4 的差異

在開始之前,先了解 Tailwind CSS 在 v4.0 有重大變化:從 JavaScript 配置轉向 CSS-first 配置。

Tailwind v3:tailwind.config.js

在 v3 中,所有客製化都在 tailwind.config.js 進行:

// tailwind.config.js (v3)
module.exports = {
  content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: '#5046e5',
      },
    },
  },
  plugins: [],
}
Code language: JavaScript (javascript)

Tailwind v4:CSS-first 配置

v4.0 改為在 CSS 檔案中直接配置,使用 @theme 指令:

/* app.css (v4) */
@import "tailwindcss";

@theme {
  --color-brand: #5046e5;
  --font-display: "Inter", sans-serif;
}
Code language: CSS (css)

讀程式碼時,如果看到 tailwind.config.js,這是 v3 專案;如果看到 CSS 中的 @theme,這是 v4 專案。兩種方式都還被支援,但 v4 推薦使用 CSS-first 方式。

本文會同時介紹兩種方式,讓你能讀懂不同版本的專案。

自訂顏色:擴展 vs 覆蓋

最常見的客製化需求是添加品牌顏色。

擴展預設調色盤(推薦)

使用 extend 可以保留 Tailwind 預設的所有顏色,只新增你需要的:

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#eff6ff',
          100: '#dbeafe',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
        },
      },
    },
  },
}
Code language: JavaScript (javascript)
/* app.css (v4) */
@theme {
  --color-brand-50: #eff6ff;
  --color-brand-100: #dbeafe;
  --color-brand-500: #3b82f6;
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
}
Code language: CSS (css)

這樣你就可以使用 bg-brand-500text-brand-700 等 class。

覆蓋預設調色盤

如果你想完全控制可用的顏色,可以覆蓋整個 colors

// tailwind.config.js (v3) - 覆蓋模式
module.exports = {
  theme: {
    // 注意:不在 extend 裡面!
    colors: {
      black: '#000',
      white: '#fff',
      primary: '#5046e5',
      secondary: '#64748b',
    },
  },
}
Code language: JavaScript (javascript)

覆蓋後,預設的 redbluegreen 等顏色都不能用了,只能使用你定義的顏色。

判斷方式: 看設定是在 theme.extend 還是直接在 theme 下:

  • theme.extend.colors:擴展,保留預設
  • theme.colors:覆蓋,取代預設

自訂間距系統

間距(spacing)影響 padding、margin、gap、width、height 等多個屬性。

新增特定間距值

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      spacing: {
        '18': '4.5rem',    // 72px
        '128': '32rem',    // 512px
      },
    },
  },
}
Code language: JavaScript (javascript)
/* app.css (v4) */
@theme {
  --spacing-18: 4.5rem;
  --spacing-128: 32rem;
}
Code language: CSS (css)

現在可以使用 p-18w-128mt-18 等 class。

間距的計算邏輯

Tailwind 預設間距是 4px 為基準:

  • spacing-1 = 0.25rem = 4px
  • spacing-4 = 1rem = 16px
  • spacing-8 = 2rem = 32px

當你看到 p-4,知道這是 16px;看到 m-8,知道這是 32px。

自訂字型

新增字型家族

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        display: ['Inter', 'sans-serif'],
        body: ['Noto Sans TC', 'sans-serif'],
      },
    },
  },
}
Code language: JavaScript (javascript)
/* app.css (v4) */
@theme {
  --font-display: "Inter", sans-serif;
  --font-body: "Noto Sans TC", sans-serif;
}
Code language: JavaScript (javascript)

使用方式:font-displayfont-body

自訂字型大小

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      fontSize: {
        'xxs': '0.625rem',     // 10px
        'display': '4.5rem',   // 72px
      },
    },
  },
}
Code language: JavaScript (javascript)

自訂斷點(Breakpoints)

預設斷點:sm: 640pxmd: 768pxlg: 1024pxxl: 1280px2xl: 1536px

新增或修改斷點

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      screens: {
        'xs': '475px',      // 新增更小的斷點
        '3xl': '1920px',    // 新增超大螢幕
      },
    },
  },
}
Code language: JavaScript (javascript)
/* app.css (v4) */
@theme {
  --breakpoint-xs: 475px;
  --breakpoint-3xl: 1920px;
}
Code language: CSS (css)

@apply 指令:提取重複樣式

@apply 讓你在 CSS 中使用 Tailwind 的 utility class:

/* components.css */
.btn {
  @apply px-4 py-2 rounded-lg font-medium transition-colors;
}

.btn-primary {
  @apply btn bg-blue-600 text-white hover:bg-blue-700;
}

.btn-secondary {
  @apply btn bg-gray-200 text-gray-800 hover:bg-gray-300;
}
Code language: JavaScript (javascript)

何時使用 @apply

適合使用的情況:

  1. 跨多個元件的重複樣式:當相同的 class 組合在多處出現且無法用元件抽象
  2. 第三方元件的基礎樣式:無法控制 HTML 結構時
  3. 全域表單元素樣式:如 input、button 的基礎樣式
/* 適合:全域的 input 樣式 */
.form-input {
  @apply w-full px-3 py-2 border border-gray-300 rounded-md
         focus:outline-none focus:ring-2 focus:ring-blue-500;
}
Code language: JavaScript (javascript)

何時避免 @apply

不建議使用的情況:

  1. 只是為了讓 HTML 看起來更乾淨:這樣做會失去 Tailwind 的優勢
  2. 只在單一地方使用的樣式:直接寫在 HTML 更直觀
  3. 可以用元件抽象的情況:React/Vue 元件比 CSS class 更好維護
/* 不推薦:單一用途的樣式 */
.hero-title {
  @apply text-4xl font-bold text-center mb-8;  /* 只用在一個地方 */
}

/* 不推薦:過度抽象 */
.card {
  @apply bg-white rounded-lg shadow-md p-6;
}
.card-header {
  @apply text-xl font-semibold mb-4;
}
.card-body {
  @apply text-gray-600;
}
/* 這些應該用 React/Vue 元件來處理 */
Code language: JavaScript (javascript)

@apply 的最佳實踐

/* 好的做法:真正需要重用的基礎樣式 */
@layer components {
  .btn {
    @apply inline-flex items-center justify-center
           px-4 py-2 rounded-lg font-medium
           transition-colors duration-200
           focus:outline-none focus:ring-2 focus:ring-offset-2;
  }
}
Code language: JavaScript (javascript)

使用 @layer components 確保樣式放在正確的層級,可以被 utility class 覆蓋。

官方插件

Tailwind 提供幾個官方插件來擴展功能。

@tailwindcss/typography

為文章內容提供優美的排版樣式,特別適合 Markdown 轉換的內容:

v3 安裝:

// tailwind.config.js
module.exports = {
  plugins: [
    require('@tailwindcss/typography'),
  ],
}
Code language: JavaScript (javascript)

v4 安裝:

/* app.css */
@import "tailwindcss";
@plugin "@tailwindcss/typography";
Code language: CSS (css)

使用方式:

<article class="prose lg:prose-xl dark:prose-invert">
  <!-- Markdown 內容會自動套用排版樣式 -->
  <h1>文章標題</h1>
  <p>這是段落內容...</p>
  <ul>
    <li>項目一</li>
    <li>項目二</li>
  </ul>
</article>
Code language: HTML, XML (xml)

prose class 會自動為:

  • 標題設定適當的字級和間距
  • 段落設定舒適的行高
  • 清單、引用區塊、程式碼區塊都有合適的樣式

@tailwindcss/forms

為表單元素提供基礎樣式重置:

v3 安裝:

// tailwind.config.js
module.exports = {
  plugins: [
    require('@tailwindcss/forms'),
  ],
}
Code language: JavaScript (javascript)

v4 安裝:

/* app.css */
@import "tailwindcss";
@plugin "@tailwindcss/forms";
Code language: CSS (css)

安裝後,<input><select><textarea> 會有一致的基礎樣式,更容易用 Tailwind class 客製化。

策略選項:

/* v4 - 只在有 class 時套用 */
@plugin "@tailwindcss/forms" {
  strategy: "class";
}
Code language: CSS (css)
  • strategy: "base":全域套用(預設)
  • strategy: "class":需要加上 form-inputform-select 等 class 才套用

效能優化

自動 Tree Shaking(JIT 模式)

從 Tailwind v3 開始,JIT(Just-in-Time)模式成為預設。它只會產生你實際使用到的 CSS class,不需要手動配置 PurgeCSS。

你需要做的是確保 content 配置正確:

// tailwind.config.js (v3)
module.exports = {
  content: [
    './src/**/*.{js,ts,jsx,tsx}',
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
}
Code language: JavaScript (javascript)

注意動態 class 名稱

JIT 透過掃描檔案來決定要產生哪些 class,所以動態組合的 class 名稱會失效:

// 錯誤:JIT 掃描不到完整的 class 名稱
const color = 'red';
<div className={`bg-${color}-500`} />

// 正確:使用完整的 class 名稱
const colorClass = {
  red: 'bg-red-500',
  blue: 'bg-blue-500',
};
<div className={colorClass[color]} />
Code language: JavaScript (javascript)

最佳實踐總結

1. Class 排序

使用 prettier-plugin-tailwindcss 自動排序 class:

npm install -D prettier prettier-plugin-tailwindcss

排序後的 class 更容易閱讀:

<!-- 排序前:雜亂 -->
<div class="p-4 flex bg-white items-center rounded-lg shadow-md justify-between">

<!-- 排序後:有邏輯順序 -->
<div class="flex items-center justify-between rounded-lg bg-white p-4 shadow-md">
Code language: HTML, XML (xml)

2. 元件化思維

優先使用框架元件來處理重複的 UI,而非 @apply

// React 元件 - 推薦
function Button({ variant = 'primary', children, ...props }) {
  const variants = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
  };

  return (
    <button
      className={`px-4 py-2 rounded-lg font-medium ${variants[variant]}`}
      {...props}
    >
      {children}
    </button>
  );
}
Code language: JavaScript (javascript)

3. 避免過度抽象

不要為了「看起來乾淨」而抽象出一堆自訂 class:

/* 過度抽象 - 不推薦 */
.container-main { @apply max-w-7xl mx-auto px-4; }
.title-lg { @apply text-2xl font-bold; }
.mt-section { @apply mt-8; }
.text-muted { @apply text-gray-500; }
Code language: JavaScript (javascript)

這樣做會:

  • 增加學習成本(團隊成員要學習你的自訂 class)
  • 失去 Tailwind 的可預測性
  • 增加維護負擔

4. 合理使用 arbitrary values

當內建值不夠用時,使用方括號語法:

<!-- 偶爾使用 - OK -->
<div class="w-[327px] h-[180px]">

<!-- 頻繁使用同樣的值 - 應該加到配置中 -->
<!-- 改為在 config 中定義 spacing 或 size -->
Code language: HTML, XML (xml)

實作練習:建立專案設計系統

以下是一個完整的客製化配置範例:

// tailwind.config.js (v3)
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f0f9ff',
          100: '#e0f2fe',
          200: '#bae6fd',
          300: '#7dd3fc',
          400: '#38bdf8',
          500: '#0ea5e9',
          600: '#0284c7',
          700: '#0369a1',
          800: '#075985',
          900: '#0c4a6e',
        },
      },
      fontFamily: {
        sans: ['Inter', 'Noto Sans TC', 'sans-serif'],
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
      borderRadius: {
        '4xl': '2rem',
      },
    },
  },
  plugins: [
    require('@tailwindcss/typography'),
    require('@tailwindcss/forms'),
  ],
}
Code language: JavaScript (javascript)
/* app.css (v4 等效配置) */
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";

@theme {
  --color-brand-50: #f0f9ff;
  --color-brand-100: #e0f2fe;
  --color-brand-200: #bae6fd;
  --color-brand-300: #7dd3fc;
  --color-brand-400: #38bdf8;
  --color-brand-500: #0ea5e9;
  --color-brand-600: #0284c7;
  --color-brand-700: #0369a1;
  --color-brand-800: #075985;
  --color-brand-900: #0c4a6e;

  --font-sans: "Inter", "Noto Sans TC", sans-serif;

  --spacing-18: 4.5rem;
  --spacing-88: 22rem;

  --radius-4xl: 2rem;
}
Code language: CSS (css)

讀程式碼時的重點

當你在閱讀 Tailwind 專案時,注意以下模式:

  1. 看配置檔案位置
    • tailwind.config.js = v3 配置
    • CSS 中的 @theme = v4 配置
  2. 判斷擴展還是覆蓋
    • theme.extend.xxx:新增,保留預設
    • theme.xxx:覆蓋,取代預設
  3. 看 @apply 使用情況
    • 少量、有意義的抽象 = 好的實踐
    • 大量、瑣碎的抽象 = 過度使用
  4. 看 content 配置
    • 確認所有使用 Tailwind 的檔案都被涵蓋
    • 漏掉會導致樣式不生效

總結

本篇介紹了 Tailwind CSS 的客製化配置與最佳實踐:

主題 重點
配置方式 v3 用 JS 配置、v4 用 CSS-first
擴展 vs 覆蓋 extend 保留預設、直接設定則覆蓋
@apply 用於真正需要重用的樣式,避免過度使用
官方插件 typography 用於文章、forms 用於表單
最佳實踐 class 排序、元件化、避免過度抽象

這是 Tailwind CSS 教學系列的最後一篇。透過這四篇文章,你已經掌握了閱讀 Tailwind 專案所需的核心知識:基礎語法、響應式設計、Flexbox/Grid 布局,以及客製化配置。當你在實際專案中遇到 Tailwind 程式碼時,這些知識將幫助你快速理解專案的設計系統和樣式架構。

Tailwind CSS 客製化配置與最佳實踐 – 進階測驗

情境題與錯誤診斷,測試你的實戰能力

1 【情境題】你接手一個專案,發現使用 bg-blue-500 沒有效果,但 bg-primary 可以正常顯示。查看配置檔案後,你推測最可能的原因是什麼?
// tailwind.config.js
module.exports = {
  theme: {
    colors: {
      primary: '#5046e5',
      secondary: '#64748b',
      white: '#fff',
      black: '#000',
    },
  },
}
2 【錯誤診斷】以下 CSS 檔案為什麼會導致 .btn 的樣式被 utility class 難以覆蓋?
/* styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

.btn {
  @apply px-4 py-2 bg-blue-600 text-white rounded-lg;
}
3 【情境題】團隊成員在專案中大量使用 @apply 建立了以下 CSS class。這種做法有什麼問題?
.page-container { @apply max-w-7xl mx-auto px-4; }
.section-title { @apply text-2xl font-bold mb-4; }
.section-subtitle { @apply text-lg text-gray-600 mb-2; }
.mt-sm { @apply mt-2; }
.mt-md { @apply mt-4; }
.mt-lg { @apply mt-8; }
.text-muted { @apply text-gray-500; }
.text-primary { @apply text-blue-600; }
4 【錯誤診斷】以下 v4 配置中,自訂的 brand 顏色為什麼無法正常使用 bg-brand-500
/* app.css */
@import "tailwindcss";

@theme {
  --brand-50: #f0f9ff;
  --brand-500: #0ea5e9;
  --brand-900: #0c4a6e;
}
5 【情境題】你需要在多個 React 元件中使用相同樣式的按鈕。以下哪種做法最符合 Tailwind 最佳實踐?
0/5
繼續加油!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *