MUI 主題 (Theme) 完整指南:從基礎到進階
本文內容基於 MUI v5.x 撰寫,同時也適用於 MUI v6.x。MUI v6 在主題系統上與 v5 保持高度相容,主要差異在於 v6 將 variants 從 components 移至 styleOverrides 內。如果你使用的是 v4 或更早版本,部分 API 可能有所不同,建議參考對應版本的官方文件。
前言
在開發 React 應用程式時,維持一致的視覺風格是一個常見的挑戰。當專案規模變大,散落在各處的顏色值、字體設定、間距數值會讓維護變得困難。MUI(Material-UI)的主題系統正是為了解決這個問題而設計的——它讓我們能夠在一個地方集中定義所有的視覺規範,並確保整個應用程式都遵循這些規範。
這篇文章整理了 MUI Theme 的核心概念與實用技巧,從最基礎的 API 使用到進階的客製化方法,希望能幫助你快速掌握 MUI 主題系統的使用方式。
本篇文章的內容主要來自 MUI 官方網站的 Theming 相關文件。你可以將這篇文章作為官方文件的快速導讀,快速了解想要實作的功能以及大致使用方法。若需要進一步深入了解,可以透過各段落提供的連結找到對應的官方文件。
快速開始
先來看一個簡單的範例,讓我們對主題的應用有一個直觀的了解:
import React from 'react';
import { createTheme, ThemeProvider, Button } from '@mui/material';
const theme = createTheme({
palette: {
primary: {
main: '#2196f3',
},
},
});
const App = () => {
return (
<ThemeProvider theme={theme}>
<Button variant="contained" color="primary">
Click me!
</Button>
</ThemeProvider>
);
};
export default App;
這個範例展示了 MUI 主題的三個核心步驟:
- 建立主題:使用
createTheme定義自訂的視覺規範 - 注入主題:使用
ThemeProvider將主題傳遞給子元件 - 使用主題:MUI 元件會自動套用主題中定義的樣式
接下來,讓我們深入了解每個核心 API 的使用方式。
核心 API
MUI 主題系統的核心由三個 API 組成:createTheme、ThemeProvider 和 useTheme。理解這三者的關係是掌握 MUI 主題的第一步。
| API | 用途 | 使用位置 |
|---|---|---|
createTheme | 建立主題配置物件 | 通常在獨立的 theme 檔案中 |
ThemeProvider | 將主題注入 React Context | 應用程式的根元件或需要不同主題的區塊 |
useTheme | 在元件中存取主題變數 | 任何需要讀取主題值的元件 |
createTheme
createTheme 是建立主題的核心函數,它接受一個配置物件作為參數,包含調色板(palette)、字體(typography)、間距(spacing)等設定:
import { createTheme } from '@mui/material';
const theme = createTheme({
palette: {
primary: {
main: '#2196f3',
},
secondary: {
main: '#f50057',
},
},
typography: {
fontFamily: 'Arial, sans-serif',
fontSize: 14,
},
spacing: 8,
});
如果需要合併多個主題配置,可以使用 deepmerge 工具:
import { deepmerge } from '@mui/utils';
import { createTheme } from '@mui/material/styles';
const theme = createTheme(deepmerge(baseTheme, customTheme));
ThemeProvider
ThemeProvider 利用 React Context 將主題傳遞給所有子元件。通常我們會在應用程式的根元件使用它:
import React from 'react';
import { ThemeProvider } from '@mui/material';
import App from './App';
import theme from './theme';
const Root = () => {
return (
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
);
};
export default Root;
我們也可以嵌套多個 ThemeProvider,內層的 theme 會覆蓋外層的 theme。這在需要局部使用不同主題時非常有用:
<ThemeProvider theme={outerTheme}>
<Checkbox defaultChecked /> {/* 使用 outerTheme */}
<ThemeProvider theme={innerTheme}>
<Checkbox defaultChecked /> {/* 使用 innerTheme */}
</ThemeProvider>
</ThemeProvider>
useTheme Hook
當你需要在元件中動態存取主題變數時,可以使用 useTheme hook:
import { useTheme } from '@mui/material/styles';
function PriceTag({ price }) {
const theme = useTheme();
return (
<span style={{
color: theme.palette.primary.main,
padding: theme.spacing(1, 2),
}}>
${price}
</span>
);
}
主題配置變數總覽
MUI 主題包含多個配置區塊,每個區塊負責不同的視覺面向:
| 配置區塊 | 用途 | 常見設定 |
|---|---|---|
| palette | 調色板 | primary、secondary、error、背景色 |
| typography | 字體排版 | fontFamily、fontSize、各級標題樣式 |
| spacing | 間距 | 基礎間距單位(預設 8px) |
| breakpoints | 響應式斷點 | xs、sm、md、lg、xl 的寬度值 |
| zIndex | 層級 | modal、drawer、tooltip 等的 z-index |
| transitions | 過渡動畫 | duration、easing 函數 |
| components | 元件樣式 | 各元件的 defaultProps 和 styleOverrides |
自訂主題變數
除了內建的配置區塊,你也可以新增自訂變數。這在需要定義專案特有的設計 token 時非常有用:
const theme = createTheme({
status: {
danger: orange[500],
},
customShadows: {
card: '0 4px 6px rgba(0, 0, 0, 0.1)',
},
});
如果使用 TypeScript,需要透過 module augmentation 擴展型別定義:
declare module '@mui/material/styles' {
interface Theme {
status: {
danger: string;
};
customShadows: {
card: string;
};
}
interface ThemeOptions {
status?: {
danger?: string;
};
customShadows?: {
card?: string;
};
}
}
Palette 調色板
Palette 是 MUI 主題中最常被客製化的部分,它定義了應用程式中使用的所有顏色。
預設顏色種類
MUI 預設提供六種語意化的顏色種類,每種都有其特定用途:
| 顏色種類 | 用途 | 預設色系 |
|---|---|---|
primary | 主要操作、品牌色 | 藍色 |
secondary | 次要操作、輔助色 | 紫色 |
error | 錯誤狀態、刪除操作 | 紅色 |
warning | 警告訊息 | 橘色 |
info | 資訊提示 | 淺藍色 |
success | 成功狀態 | 綠色 |
每個顏色種類都包含以下屬性:
interface PaletteColor {
light?: string; // 淺色變體
main: string; // 主要顏色(必填)
dark?: string; // 深色變體
contrastText?: string; // 對比文字顏色
}
三種設定顏色的方式
方式一:使用 MUI 內建顏色
最簡單的方式是直接引入 MUI 提供的 color 物件,它會自動包含 light