主题
前言
Simple 模板项目提供了一套灵活的主题与暗黑模式适配机制。它巧妙地结合了原生 CSS 变量(CSS Custom Properties)、Tailwind CSS 实用工具类、Element Plus 以及动态运行时换肤机制,使得开发者可以轻易地定制整站色调。
主题系统简介
模板项目的主题系统由以下三个核心层面共同构建:
- CSS 变量系统:定义在
src/styles/var.css与src/styles/dark.css中。通过在根节点(:root)与深色类选择器(html.dark)下重写同名 CSS 变量,实现全局样式的“明/暗切换”。 - Tailwind CSS (v4) 联动:在
src/styles/tailwind.css的@theme部分中,通过原生变量var(--u-...)将自定义 CSS 变量注册到 Tailwind 的类名系统中。这样,开发者在业务代码中即可通过如bg-body或text-tx-primary的实用程序类,自动获得符合明暗模式的颜色表现。 - 运行时主题色生成:通过前端辅助函数根据用户指定的主题色(如 Primary 品牌色),在运行时计算出 Element Plus 规范所需的明暗梯度色,并动态插入
<style id="theme-vars">覆盖默认表现。
主题样式变量结构
项目的核心基础变量全部以 --u- 前缀命名,从而与浏览器默认样式和框架底层的 Element Plus 变量区分。
样式变量分类列表
以下是模板中最为常用的关键 CSS 变量及其含义:
| 变量分类 | CSS 变量名称 | 默认明色值 (var.css) | 默认暗色值 (dark.css) | 样式含义与用途 |
|---|---|---|---|---|
| 页面与容器背景 | --u-bg-color-page | #fff | #0a0a0a | 页面最底层背景色 |
--u-bg-color | #fff | #1d2124 | 基础卡片与容器背景色 | |
--u-bg-color-overlay | #fff | #1d1e1f | 弹出层、对话框、下拉菜单背景色 | |
| 文本字色 | --u-text-color-primary | #1d2130 | #e5eaf3 | 主要文字、标题色 |
--u-text-color-regular | #666 | #cfd3dc | 常规正文、描述字色 | |
--u-text-color-secondary | #4e5968 | #a3a6ad | 次要文字字色 | |
--u-text-color-placeholder | #a8abb2 | #8d9095 | 占位文字、禁用状态字色 | |
| 边框与填充 | --u-border-color | #dcdfe6 | #4c4d4f | 基础边框色 |
--u-border-color-light | #e4e7ed | #414243 | 浅边框色 | |
--u-fill-color | #f0f2f5 | #303030 | 区域填充色 | |
--u-fill-color-light | #f8f8f8 | #262727 | 浅层填充色(如表格悬停、条纹) | |
| 阴影级别 | --u-box-shadow | 浅灰色阴影 | 深黑色阴影 | 基础卡片阴影 |
明暗模式切换原理
模板项目整合了 Vueuse、Pinia 以及系统偏好偏好,提供了极其顺畅的明暗转换。
颜色模式与核心变量
系统配置项中支持三种颜色模式:
light:强制使用明色主题;dark:强制使用暗色主题;system:跟随操作系统当前的明暗状态偏好。
该参数定义在 src/config/setting.ts 中,并在 Pinia 状态树的 settingStore.colorMode 中进行维护。
全局类名与样式切换流
明暗主题的自动切换和解析流程如下:
获取原始偏好:系统初始化或用户手动切换模式时,读取全局
colorMode配置以及系统级的prefersDark状态偏好。状态逻辑解析:调用
resolveIsDark(mode, systemPrefersDark)辅助函数计算得出最终是否应当启用暗色的布尔值(isDark)。切换全局样式类:
- 若
isDark为true(启用暗色):通过 DOM 操作为html根节点添加class="dark"。 - 若
isDark为false(启用明色):将class="dark"从html根节点中移除。
- 若
生成运行时变量:同步调用
setTheme函数重新计算主色彩梯度并在document.head中动态插入或更新相应的 CSS 变量样式,确保明暗状态下 Element Plus 和系统主色的完美呈现。在顶层组件
src/App.vue中,使用 Vueuse 的usePreferredDark响应式监听系统的暗黑偏好:tsconst prefersDark = usePreferredDark() watch( [prefersDark, () => settingStore.colorMode], () => { settingStore.applyThemeForResolvedDark(prefersDark.value) }, { immediate: true } )applyThemeForResolvedDark接收系统偏好,结合用户在 store 中的colorMode设置决定是否启用暗色,最终通过document.documentElement.classList.toggle('dark', isDark)切换html上面的dark类。当
html带有.dark类名时,:root.dark中的 CSS 变量值(来自dark.css)将覆盖:root下的明色变量值,整站外观自适应转换。
运行时主题色动态生成
除了简单的明暗模式,模板项目还支持在运行时动态地对主色调(Primary 品牌色)及其他辅助状态色(Success, Warning, Danger 等)进行“品牌换肤”。
主题梯度色计算逻辑
动态生成变量的核心文件在 src/utils/theme.ts。
在运行时更改品牌色时,系统会加载 css-color-function 插件,根据基色和混色配置,通过 shade 和 tint 变换函数计算出一组梯度配色。 例如,以 lightConfig 为例,生成的变量规则为:
dark-2:shade(20%)light-3:tint(30%)light-5:tint(50%)light-7:tint(70%)light-8:tint(80%)light-9:tint(90%)
而在暗黑模式下,配置会切换为 darkConfig,以获取反向更深/更亮梯度色,确保深色模式下按钮及文字对比度清晰。
动态样式表插入机制
当品牌色变量被 generateVars 计算完毕后,将调用 setTheme 将这些变量渲染为 CSS 的 :root 代码段,并追加到 <head> 中:
export const setTheme = (options: Record<string, string>, isDark = false) => {
// 根据当前色彩选项与明暗状态,得到完整的 CSS 变量 Mapping 键值对
const varsMap = Object.keys(options).reduce((prev, key) => {
return Object.assign(prev, generateVars(options[key], key, isDark))
}, {})
// 格式化为 CSS 样式内容
let theme = Object.keys(varsMap).reduce((prev, key) => {
const color = colors.convert(varsMap[key])
return `${prev}${key}:${color};`
}, '')
theme = `:root{${theme}}`
// 创建或更新动态样式标签插入到文档头部
let style = document.getElementById('theme-vars')
if (style) {
style.innerHTML = theme
return
}
style = document.createElement('style')
style.setAttribute('type', 'text/css')
style.setAttribute('id', 'theme-vars')
style.innerHTML = theme
document.head.append(style)
}这套动态生成的 --u-color-primary 变量会被 Element Plus 以及 Tailwind CSS 底层捕获,达到一键换肤的效果。
如何自定义主题
修改默认颜色配置
若需要在初始状态修改默认的品牌色彩或明暗模式配置,请直接编辑项目根配置 src/config/setting.ts 中的 defaultSetting 项:
const defaultSetting = {
// ...
theme: '#2F54EB', // 修改默认系统主题品牌色
successTheme: '#42B200', // 修改默认成功主题色
colorMode: 'system', // 修改默认色彩模式 (light / dark / system)
}覆盖特定 CSS 变量
- 若需修改全局的明色样式或特定组件基础色,可在
src/styles/var.css中修改:css:root { /* 覆盖主要字色为极深蓝色 */ --u-text-color-primary: #0f172a; } - 若需自定义或修补组件库在深色模式下的效果(例如编辑器 WangEditor ),可修改
src/styles/dark.css(注意:在src/styles/index.scss中需取消对dark.css的导入注释):css:root.dark { /* 覆盖编辑器区域在暗黑下的背景 */ --w-e-textarea-bg-color: var(--u-bg-color); --w-e-textarea-color: var(--u-text-color-primary); }
联动 Tailwind CSS
如果您在写自定义组件时想利用配置系统中的颜色变量,我们强烈推荐使用 Tailwind 实用程序类。
因为在 src/styles/tailwind.css 中已经配置了变量桥接映射:
@theme {
/* 桥接自定义的 CSS 变量到 Tailwind 类名系统中 */
--color-body: var(--u-bg-color);
--color-page: var(--u-bg-color-page);
--color-tx-primary: var(--u-text-color-primary);
--color-tx-regular: var(--u-text-color-regular);
}您在业务 Vue 页面中,直接使用:
<template>
<!-- 当系统处于明色时背景为白色,字色为深灰;暗色时背景变为 #1d2124,字色变为 #e5eaf3 -->
<div class="bg-body text-tx-primary p-4 border border-br">
<h3>卡片标题</h3>
<p class="text-tx-regular">常规描述正文内容...</p>
</div>
</template>这种设计最大程度做到了“样式逻辑与业务表达分离”,降低了多主题、多明暗状态下的心智负担。