# Halo 黑暗模式插件 — 设计文档 > 版本:v0.2.0-draft(基于 create-halo-plugin + dev-skills 调查更新) > 日期:2026-08-06 > 状态:待审阅 > 上一步:[调查文档](./调查文档.md)(含 0.4 节补充调查更新) --- ## 目录 1. [设计目标与范围](#1-设计目标与范围) 2. [技术架构](#2-技术架构) 3. [CSS 变量体系设计](#3-css-变量体系设计) 4. [黑暗模式调色板](#4-黑暗模式调色板) 5. [组件覆盖策略](#5-组件覆盖策略) 6. [切换器 UI 设计](#6-切换器-ui-设计) 7. [路由与菜单](#7-路由与菜单) 8. [偏好持久化](#8-偏好持久化) 9. [项目文件结构](#9-项目文件结构) 10. [实现阶段划分](#10-实现阶段划分) 11. [测试策略](#11-测试策略) 12. [兼容性矩阵](#12-兼容性矩阵) --- ## 1. 设计目标与范围 ### 1.1 核心目标 将 Halo 后台管理面板(Console)从纯浅色模式改造为支持浅色/黑暗双模式,**不修改 Halo 核心代码**,完全通过插件机制实现。 ### 1.2 范围界定 | 范围 | 包含 | 不包含 | |------|------|--------| | 页面 | Halo Console(后台管理)全体页面 | 用户中心 (uc-src)、前台主题 | | 组件 | Halo 核心组件 + `@halo-dev/components` 组件库 | 第三方插件自有 UI | | 编辑器 | FormKit 表单 + 富文本编辑器 | 编辑器内容区自定义样式 | | 模式 | 浅色 ↔ 黑暗手动切换 + 跟随系统 | 定时切换、多主题 | ### 1.3 非功能性目标 - **性能**:CSS 变量切换应 < 50ms,无可见闪烁(FOUC) - **可访问性**:黑暗模式下所有文本满足 WCAG AA 对比度要求(≥ 4.5:1) - **兼容性**:支持 Halo ≥ 2.23.0(对应 plugin-starter 的版本约束) - **可维护性**:CSS 变量体系命名清晰,一个语义变量对应一个视觉属性 ### 1.4 反目标(明确不做) - ❌ 不美化 UI(不改变布局、圆角、间距、字体等) - ❌ 不添加任何视觉装饰效果 - ❌ 不修改 Halo 组件库源码 - ❌ 不支持前台主题的暗色化 --- ## 2. 技术架构 ### 2.1 整体架构图 ``` ┌──────────────────────────────────────────────────────────┐ │ 插件边界 │ │ │ │ ┌─────────────┐ ┌──────────────────────────────────┐ │ │ │ Java 后端 │ │ 前端 (ui/) │ │ │ │ │ │ │ │ │ │ BasePlugin │ │ ┌────────────────────────────┐ │ │ │ │ ├ start() │ │ │ index.ts (definePlugin) │ │ │ │ │ └ stop() │ │ │ ├ components: { │ │ │ │ │ │ │ │ │ ThemeToggle │ │ │ │ │ (极简骨架) │ │ │ │ } │ │ │ │ └─────────────┘ │ │ ├ routes: [设置页面] │ │ │ │ │ │ └ extensionPoints: {} │ │ │ │ │ └────────────────────────────┘ │ │ │ │ │ │ │ │ ┌────────────────────────────┐ │ │ │ │ │ composables/ │ │ │ │ │ │ ├ useDarkMode.ts │ │ │ │ │ │ └ useSystemPreference.ts │ │ │ │ │ └────────────────────────────┘ │ │ │ │ │ │ │ │ ┌────────────────────────────┐ │ │ │ │ │ styles/ │ │ │ │ │ │ ├ variables.css │ │ │ │ │ │ ├ dark-theme.css │ │ │ │ │ │ ├ overrides/ │ │ │ │ │ │ │ ├ layout.css │ │ │ │ │ │ │ ├ components.css │ │ │ │ │ │ │ ├ formkit.css │ │ │ │ │ │ │ ├ editor.css │ │ │ │ │ │ │ └ scrollbar.css │ │ │ │ │ │ └ index.css │ │ │ │ │ └────────────────────────────┘ │ │ │ └──────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 注入方式(Halo 插件加载机制自动处理) │ │ │ │ CSS → /apis/.../ui-plugins/-/bundle.css │ │ │ │ JS → /apis/.../ui-plugins/-/bundle.js │ │ │ └──────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ ``` ### 2.2 运行时数据流 ``` ┌──────────────┐ │ App 启动 │ └──────┬───────┘ │ ┌──────▼───────┐ │ 读取持久化偏好 │ │ localStorage │ │ (默认: system)│ └──────┬───────┘ │ ┌────────────┼────────────┐ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ 浅色 │ │ 黑暗 │ │ 跟随系统 │ │ theme= │ │ theme= │ │ theme= │ │ "light" │ │ "dark" │ │ "auto" │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ ┌─────▼──────┐ │ │ │ 监听 match │ │ │ │ Media query│ │ │ └─────┬──────┘ │ │ │ └────────────┼────────────┘ │ ┌──────▼───────┐ │ 设置 │ │ document │ │ .documentEl │ │ 的 data attr │ │ data-halo- │ │ theme="dark" │ │ 或移除该属性 │ └──────┬───────┘ │ ┌──────▼───────┐ │ CSS 变量切换 │ │ :root vs │ │ [data-halo- │ │ theme="dark"]│ └──────────────┘ ``` ### 2.3 关键技术决策 | 决策点 | 选择 | 理由 | |--------|------|------| | 主题切换方式 | `data-halo-theme` 属性 | 前缀避免冲突,属性选择器高效 | | 颜色系统 | CSS Variables + OKLCH 颜色空间 | 感知均匀,暗色模式天然适配 | | 切换状态管理 | Vue composable (`useDarkMode`) | 轻量,无 Pinia 依赖,方便跨组件复用 | | 持久化存储 | `localStorage` | 极简,零后端依赖,立即可用 | | 系统偏好监听 | `matchMedia('prefers-color-scheme: dark')` | 标准 API,所有现代浏览器支持 | | 初始加载防闪烁 | ` ``` **注意**:由于插件 bundle 是异步加载的(`useScriptTag`),FOUC 风险需要通过以下方式缓解: - CSS 变量切换是瞬时的(< 1 帧),即使有短暂浅色闪现,用户体感为"页面加载完成" - 后续可通过向 Halo 提交 PR 在 `console.html` 添加 `