深色模式
Sakana Element 内置了完整的深色模式支持,采用 Catppuccin Mocha 风格的配色方案。主题系统提供三种模式 —— light、dark 和 system —— 并自动将选择保存到 localStorage,同时支持检测系统偏好。
| 名称 | 分类 | 说明 | 类型 |
|---|---|---|---|
theme | 暴露 | 当前主题设置 | ComputedRef<'light' | 'dark' | 'system'> |
isDark | 暴露 | 当前是否为深色模式 | ComputedRef<boolean> |
prefersDark | 暴露 | 操作系统是否偏好深色模式 | Ref<boolean> |
prefers | 暴露 | 操作系统配色方案偏好 | Ref<'light' | 'dark'> |
setTheme | 方法 | 设置主题为 'light'、'dark' 或 'system' | (theme: Theme) => void |
toggleTheme | 方法 | 在 light 和 dark 之间切换 | () => void |
基本用法
使用 useTheme 组合式函数来切换主题。主题状态在所有组件之间共享,并持久化到 localStorage。
<template>
<div class="demo-dark-mode">
<div class="demo-dark-mode__status">
<span>Theme: <code>{{ theme }}</code></span>
<span>isDark: <code>{{ isDark }}</code></span>
</div>
<div class="demo-dark-mode__actions">
<px-button @click="toggleTheme">Toggle Theme</px-button>
<px-button type="primary" @click="setTheme('light')">Light</px-button>
<px-button type="primary" @click="setTheme('dark')">Dark</px-button>
<px-button type="info" @click="setTheme('system')">System</px-button>
</div>
</div>
</template>
<script setup lang="ts">
import { useTheme } from 'sakana-element';
import { useData } from 'vitepress';
import { watch } from 'vue';
const { isDark, theme, toggleTheme, setTheme } = useTheme();
const { isDark: vpIsDark } = useData();
// Sync VitePress → useTheme (immediate: true aligns initial state)
watch(
vpIsDark,
(dark) => {
if (dark !== isDark.value) setTheme(dark ? 'dark' : 'light');
},
{ immediate: true },
);
// Sync useTheme → VitePress
watch(isDark, (dark) => {
if (dark !== vpIsDark.value) vpIsDark.value = dark;
});
</script>
<style scoped>
.demo-dark-mode__status {
display: flex;
gap: 20px;
margin-bottom: 16px;
font-size: 14px;
}
.demo-dark-mode__status code {
padding: 2px 6px;
border: 1px solid var(--px-border-color-lighter);
background: var(--px-fill-color-lighter);
}
.demo-dark-mode__actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
</style>主题模式
setTheme 函数接受三个值:
| 模式 | 说明 |
|---|---|
'light' | 强制浅色模式,不跟随系统设置 |
'dark' | 强制深色模式,不跟随系统设置 |
'system' | 自动跟随用户操作系统的配色方案 |
ts
import { useTheme } from 'sakana-element'
const { setTheme, toggleTheme, isDark, theme } = useTheme()
// 设置指定模式
setTheme('dark')
// 在浅色 ↔ 深色之间切换(不涉及 system)
toggleTheme()
// 读取当前状态
console.log(theme.value) // 'light' | 'dark' | 'system'
console.log(isDark.value) // true | false持久化
调用 setTheme() 时,选择的模式会保存到 localStorage 的 px-theme 键下。页面刷新后主题会自动恢复。
系统偏好检测
useSystemTheme 组合式函数提供对用户操作系统配色方案的只读访问。当系统偏好发生变化时,它会响应式地更新。
vue
<script setup lang="ts">
import { useSystemTheme } from 'sakana-element'
const { prefersDark } = useSystemTheme()
</script>
<template>
<p>系统偏好深色模式:{{ prefersDark }}</p>
</template>什么时候用哪个?
使用 useTheme 来控制主题(切换、持久化、应用 CSS 类)。使用 useSystemTheme 仅需要读取系统偏好而不改变任何东西时 —— 例如,显示"您的系统处于深色模式"的提示。
工作原理
当深色模式激活时,Sakana Element 会在 <html> 元素上添加 px-dark 类。所有组件样式都引用 CSS 自定义属性(变量),这些变量在 .px-dark 下重新定义:
:root → 浅色模式变量(默认)
.px-dark, .dark → 深色模式变量覆盖这意味着主题切换是纯 CSS 实现的 —— 不需要组件重新渲染。
自定义颜色
你可以覆盖任意一个 CSS 变量来定制主题。在你的应用全局 CSS 中定义覆盖即可:
<template>
<div class="demo-custom-vars">
<div class="demo-custom-vars__section">
<h4>Default Theme</h4>
<div class="demo-custom-vars__row">
<px-button type="primary">Primary</px-button>
<px-button type="success">Success</px-button>
<px-button type="warning">Warning</px-button>
<px-button type="danger">Danger</px-button>
</div>
</div>
<div class="demo-custom-vars__section custom-theme">
<h4>Custom Theme (overridden variables)</h4>
<div class="demo-custom-vars__row">
<px-button type="primary">Primary</px-button>
<px-button type="success">Success</px-button>
<px-button type="warning">Warning</px-button>
<px-button type="danger">Danger</px-button>
</div>
</div>
<div class="demo-custom-vars__code">
<code>.custom-theme { --px-color-primary: #e64553; ... }</code>
</div>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.demo-custom-vars {
display: flex;
flex-direction: column;
gap: 20px;
}
.demo-custom-vars__section {
padding: 16px;
border: 2px solid var(--px-border-color-lighter);
background: var(--px-bg-color);
}
.demo-custom-vars__section h4 {
margin: 0 0 12px;
font-size: 14px;
color: var(--px-text-color-primary);
}
.demo-custom-vars__row {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.demo-custom-vars__code {
padding: 10px 14px;
font-size: 12px;
background: var(--px-fill-color-lighter);
border: 1px solid var(--px-border-color-lighter);
}
.demo-custom-vars__code code {
color: var(--px-text-color-regular);
}
/* Custom theme overrides — this is what we're demonstrating */
.custom-theme {
--px-color-primary: #e64553;
--px-color-primary-dark: #c73a47;
--px-color-primary-light-3: #eb6a76;
--px-color-primary-light-5: #f08f98;
--px-color-primary-light-7: #f5b4ba;
--px-color-primary-light-8: #f8c7cc;
--px-color-primary-light-9: #fce3e5;
--px-color-success: #209fb5;
--px-color-success-dark: #1a8599;
--px-color-warning: #df8e1d;
--px-color-warning-dark: #bf7a19;
--px-color-danger: #d20f39;
--px-color-danger-dark: #b30d31;
}
</style>可用变量分类
| 分类 | 示例变量 | 说明 |
|---|---|---|
| 主色 | --px-color-primary、--px-color-primary-dark | 品牌强调色 |
| 成功色 | --px-color-success、--px-color-success-dark | 成功状态颜色 |
| 警告色 | --px-color-warning、--px-color-warning-dark | 警告状态颜色 |
| 危险色 | --px-color-danger、--px-color-danger-dark | 错误/危险状态颜色 |
| 信息色 | --px-color-info、--px-color-info-dark | 信息状态颜色 |
| 背景色 | --px-bg-color、--px-bg-color-page、--px-bg-color-overlay | 页面和容器背景色 |
| 文字色 | --px-text-color-primary、--px-text-color-regular 等 | 排版颜色 |
| 边框色 | --px-border-color、--px-border-color-light 等 | 边框和分隔线颜色 |
| 填充色 | --px-fill-color、--px-fill-color-light 等 | 填充和背景强调色 |
TIP
每个语义颜色(primary、success 等)都有 -dark 深色变体和 -light-3 到 -light-9 的浅色变体。覆盖这些变体可以在 hover、disabled 和 focus 状态下保持一致的外观。