主題系統
主題由 swift.config.json 的 theme.mode 單旋鈕驅動,一個欄位同時決定三件事:載入哪套 token、宣告什麼 color-scheme、是否提供切換器。
theme.mode 四選一
// nuxt.config.ts
swiftConfig: {
theme: {
mode: 'toggle', // 'system' | 'toggle' | 'dark' | 'light'
default: 'auto', // 僅 toggle:切換器初始態 'auto' | 'light' | 'dark',預設 'auto'
toggleStates: 3, // 僅 toggle:3=三態(可回自適應)/ 2=兩態(僅明暗),預設 3
}
}
mode | 載入的 token | color-scheme | 切換器 | 典型場景 |
|---|---|---|---|---|
'system' | 淺 + 暗 | 暗色語境下 dark(跟隨系統) | ❌ 不提供 | 想跟隨系統、但不給使用者手動切 |
'toggle' | 淺 + 暗 | 暗色語境下 dark | ✅ useTheme() + SwThemeSwitch | 使用者可切明暗並記憶 |
'dark' | 固定深色 | dark | ❌ | 固定深色站(調色盤由 applier overrides 提供) |
'light'(starter 預設) | 固定淺色 | light | ❌ | 固定淺色站,公司多數專案 |
theme 只接受物件形態。固定單主題站直接寫 { mode: 'light' } 或 { mode: 'dark' }。
每種 mode 都會讓原生 UI(捲軸、下拉、日期選擇器等)跟對,避免「深色頁面配淺色捲軸」這類割裂,但宣告方式按 mode 分兩類:固定
dark/light在:root上常駐宣告;system/toggle只在暗色語境(@media (prefers-color-scheme: dark)與[data-theme='dark'])宣告color-scheme: dark,淺色語境不宣告、走瀏覽器預設(等效淺色)。
運作原理
toggle 模式下,框架在 <html> 上設定 data-theme="light|dark",CSS 用屬性選擇器覆蓋變數。框架還會自動注入一段 head 內聯 bootstrap script:首幀渲染前同步讀取 localStorage 中的使用者偏好並搶先設定 data-theme,避免「手選主題與系統偏好相反時整頁載入閃一幀錯色」(FOUC)——無需業務配置。變數覆蓋示例:
:root {
--background: #ffffff;
--foreground: #1a1a1a;
}
[data-theme='dark'] {
--background: #0f0f12;
--foreground: #e5e7eb;
}
auto(跟隨系統)用 prefers-color-scheme 媒體查詢偵測系統偏好,並在系統偏好變化時自動切換。固定 dark / light 模式則由框架注入對應的 color-scheme 宣告、不掛 data-theme 切換邏輯。
useTheme() 使用
<script setup lang="ts">
const { theme, resolvedTheme, mode, toggleTheme, setTheme } = useTheme()
</script>
<template>
<p>當前主題:{{ theme }}(實際明暗:{{ resolvedTheme }})</p>
<!-- 僅 toggle 模式下 toggleTheme / setTheme 生效;其它模式為 no-op -->
<button @click="toggleTheme()">切換主題</button>
<button @click="setTheme('dark')">深色</button>
<button @click="setTheme('light')">淺色</button>
<button @click="setTheme('auto')">跟隨系統</button>
</template>
theme是使用者選擇的狀態('auto' | 'light' | 'dark'),resolvedTheme是當前實際明暗('light' | 'dark',auto態取系統偏好)——切 logo / 插畫按resolvedTheme判斷。toggleTheme()/setTheme()僅在mode: 'toggle'時生效,其它模式為 no-op(主題由 mode 鎖定)。
詳細 API 參見 useTheme() composable 文件。
內建切換器 SwThemeSwitch
不想自己寫切換按鈕時,直接放框架內建的 SwThemeSwitch——它由 useTheme() 驅動、自 gate:僅 mode: 'toggle' 時渲染按鈕,其它模式渲染為空。改 theme.mode 配置,切換器自動出現 / 消失,無需改模板。
<template>
<!-- 預設內聯 SVG 圖示(sun / moon / auto 半圓);mode≠toggle 時自動不顯示 -->
<SwThemeSwitch />
<SwThemeSwitch :size="22" />
<!-- 框架不綁圖示庫:用具名 slot 傳入自己圖示庫的圖示 -->
<SwThemeSwitch>
<template #light><PhSun :size="18" /></template>
<template #dark><PhMoon :size="18" /></template>
<template #auto><PhCircleHalf :size="18" /></template>
</SwThemeSwitch>
</template>
sizeprop:預設內聯圖示尺寸(px,預設 18;用 slot 傳自訂圖示時不生效)。- slot
#light/#dark/#auto:覆蓋對應態圖示,作用域提供{ theme, resolved }(#auto僅三態出現)。 - 皮膚走
--sw-theme-switch-*token(尺寸 / 圓角 / hover 背景等),applier 可覆蓋。
持久化
使用者選擇存在 localStorage 的 theme key,重新整理後自動恢復。為在首屏 inline script 階段同步讀取避免 FOUC,useTheme() 用裸 localStorage(不走加密快取 util)——這是框架認可的例外,業務做主題切換時與它共用同一 key 即可。
自訂主題變數
/* 在 assets/styles/global.css 中覆蓋框架預設變數 */
:root {
--primary: #6366f1;
}
[data-theme='dark'] {
--primary: #818cf8;
}
固定 dark 模式下,直接在 :root 定義深色調色盤即可(無需 [data-theme] 選擇器,因為不切換)。