# Halo 暗色模式残留排查报告

> 排查时间：2026-08-07
> 排查环境：腾讯云生产站 `blog.liuhangyv.top`（Halo Pro 2.24.2）
> 排查方式：Playwright 自动化全路由扫描，共 92 个后台路由

## 一、结论摘要

1. **部署版本没有问题**。服务端实际加载的 `bundle.css` 与本仓库 `ui/build/dist/style.css` 的 194 条暗色规则完全一致，不存在"部署了旧包"的情况。
2. **73 个后台路由存在深浅色残留**，19 个路由完全干净（主要是 Shop 插件全家桶、快照页、权限页）。
3. 残留可归纳为 **3 类根因**：
   - 插件 CSS 加载顺序在最前，同特异性规则被后加载的 Halo 核心样式覆盖；
   - UnoCSS 哈希类前缀已从 `i-*` 变为 `uno-*`，现有兜底规则匹配不到；
   - 第三方插件页面（AstraHub、RSS 订阅、私密文章、AI 评论等）基本没有覆盖。

## 二、扫描方法与产物

### 方法

1. Playwright 启动持久化 Edge 上下文，复用已登录会话；
2. 从 Vue Router 读取全部注册路由（92 个），逐页加载；
3. 每页强制 `data-halo-theme="dark"`，等待网络空闲后扫描；
4. 扫描规则：可见且尺寸大于 50×20 的元素，背景 RGB 均 >235 记为浅色背景残留，直接文本颜色 RGB 均 <70 记为深色文字残留；
5. 每页截图存档，结果按页面 + 元素分组去重。

### 产物（均在 `workplace/`）

| 文件 | 说明 |
|------|------|
| `scan_dark.py` | 全路由扫描脚本 |
| `scan-results.json` | 原始扫描结果（92 页 × 元素级） |
| `aggregate.txt` | 按元素/类名/问题聚合后的明细 |
| `shots/*.png` | 92 页深色模式截图 |
| `deployed-bundle.css` | 服务端实际部署的 CSS 快照 |
| `probe_conflict.py` / `fetch_bundle.py` | 样式表加载顺序与版本对比脚本 |

## 三、总体数据

| 指标 | 数值 |
|------|------|
| 扫描路由数 | 92 |
| 存在残留的路由 | 73 |
| 完全干净的路由 | 19 |
| 去重后的残留组 | 134 |
| 页面 × 元素残留条目 | 256 |
| 影响页面最多的残留 | 侧边栏 `.menu-item-title.active` 高亮背景（68 页） |
| 次多 | `.empty-title` 深色文字（16 页） |

无残留的 19 个路由：`/console/403`、Shop 插件全部 11 个页面、`/console/app-store/privacy-policy`、`/console/posts/snapshots`、`/console/single-pages/snapshots`、`/console/users/auth-providers`、`/console/users/roles`。

## 四、根因分析

### 根因 1（P0）：插件 CSS 加载顺序在最前，同特异性规则被 Halo 核心样式覆盖

**证据**（来自 `probe_conflict.py`）：

- 插件 `bundle.css` 是 `document.styleSheets` 的第 0 张表；
- Halo 核心样式 `process-bar-DsZ2lvXx.css` 是第 9 张表，加载更晚；
- 双方存在同特异性规则，CSS 级联规则让"后加载者"胜出：

| 规则 | 特异性 | 结果 |
|------|--------|------|
| Halo：`.description-item-wrapper .description-item__label { color: rgb(17 24 39) }` | (0,2,0) | 胜出 |
| 插件：`[data-halo-theme="dark"] .description-item__label { color: var(--halo-text-secondary) }` | (0,2,0) | 被覆盖 |

**受影响页面**：`/console/overview`、`/console/schedule-calendar`、`/console/theme` 的详情描述项（名称、Halo、站点地址等文字仍是深色）。

**修复建议**：

- 对这类核心语义类统一加 `!important`；
- 或把前缀从 `[data-halo-theme="dark"]` 提升为 `html[data-halo-theme="dark"]`，把特异性从 (0,2,0) 提高到 (0,2,1)。

推荐两者并用（提高特异性 + `!important` 双保险），因为 Halo 核心样式后续仍可能继续调整。

### 根因 2（P0）：UnoCSS 哈希类前缀已变化，现有兜底规则失效

**证据**：

- 大量残留元素的类名是 `uno-*` 前缀（如 `uno-ga61as`、`uno-529526`、`uno-b60d0h`）；
- `plugin-pages.css` 中的兜底规则只覆盖 `[class*="i-"]`，这是旧版 UnoCSS 的哈希前缀；
- 部署 CSS 探针确认：`menu-item-title`、`empty-title`、`alert-wrapper` 三个关键字在暗色规则中完全不存在。

**受影响页面**：AI Foundation 全家桶（每页 3–24 处）、数据迁移、装备/关注/照片/时间线/投票的卡片头部"新增"栏、SummaraidGPT 等。

**修复建议**：

- 新增 `[class*="uno-"]` 的兜底覆盖（背景、文字、边框三件套），并加 `!important`；
- 保留 `i-*` 规则，因为扫描中仍有少量 `i-*` 哈希（如 `.i-p4hnaq`）在真实页面出现，两个前缀并存。

### 根因 3（P0）：核心语义类缺覆盖

以下类在部署 CSS 中**完全没有暗色规则**，属于新增覆盖而非覆盖失效：

| 类名 | 残留内容 | 影响页面 |
|------|----------|----------|
| `.menu-item-title.active` | 高亮背景 `rgb(243,244,246)` | 68 页 |
| `.empty-title` | 文字 `rgb(17,24,39)` | 16 页 |
| `.alert-wrapper` / `.alert-default` | 背景 `rgb(249,250,251)` | 3 页（概览、许可证、导入） |
| `.description-item__label/content` | 文字 `rgb(17,24,39)` | 3 页（同特异性失效，见根因 1） |

**修复建议**：

- 侧边栏高亮：覆盖 `.menu-item-title.active`（含 `:hover`），用 `--halo-menu-item-active` 变量；
- 空状态：覆盖 `.empty-title`，用 `--halo-text-secondary`；
- 提示条：覆盖 `.alert-wrapper` 及各变体的背景/边框/文字。

### 根因 4（P1）：第三方插件页面几乎未覆盖

| 插件/页面 | 残留类名 | 说明 |
|-----------|----------|------|
| AstraHub + 心愿便签 | `.ah-card`、`.ah-topbar`、`.ah-float-nav`、`.ah-topbar-brand` | 两插件共用同一套 `ah-*` UI，覆盖一次可同时生效 |
| RSS 订阅 | `.subscription-panel`、`.feed-toolbar`、`.feed-status-tabs`、`.feed-stream`、`.feed-brief__title` | 整个页面几乎整片浅色 |
| 私密文章 | `.focus-card`、`.overview-card`、`.list-card`、`.empty-state` | 半透明白背景叠在深色上，文字也是深色 |
| AI 评论自动处理 | `.setting-panel`、`.form-row`、`.sidebar-card`、`.tabs-wrap`、`.list-col`、`.reply-card` | 设置页和日志页整片浅色 |
| 数据工坊 | `.modal-content`、`.uno-*` 卡片 | 弹窗与主内容区均残留 |
| 代码注入器 | `.uno-*` 侧栏/编辑区 | 整页浅色 |
| Meilisearch 概览 | `.uno-*` | 卡片与标题残留 |
| 日志查看器 | `.monaco-editor`、`.margin`、`.lines-content` | **Monaco Editor 自带独立主题系统**，仅靠 CSS 覆盖很难稳定 |
| 导入/存储工具 | `.uno-*` | 提示卡片、分页栏残留 |

**修复建议**：

- `ah-*`、`feed-*`、`focus-card/overview-card/list-card`、`setting-panel/form-row/sidebar-card` 等语义类按插件页面补 `!important` 规则；
- Monaco 不要硬啃 CSS，优先在 JS 里监听主题切换并调用 `monaco.editor.setTheme('vs-dark')`，或加载官方 dark 主题 CSS；
- 每个插件补完后再跑一次 `scan_dark.py` 验证零残留。

### 根因 5（P2）：历史遗留规则与自相矛盾的选择器

- `components.css` 中大量 `.v-*`（Vuetify 类）在 Halo 2.25 的真实 DOM 中不存在，属无效规则（CLAUDE.md 已记录）；
- `[class*="tag-"]`、`[class*="modal"]` 等宽泛匹配容易误伤，建议逐步收紧；
- `utilities.css` 与 `halo-core.css` 对链接色的规则互相覆盖，最终生效结果不明确；
- `halo-core.css` 的 `html, body` 编译后为 `[data-halo-theme="dark"] html`，该选择器**永远不匹配**（html 元素不会是其自身的后代），根背景兜底实际只靠 `body` 一条，页面在特殊滚动场景下仍有露白风险。

## 五、修复优先级清单

### P0（一次重构后全站收益最大）

1. 全局暗色规则前缀从 `[data-halo-theme="dark"]` 升级为 `html[data-halo-theme="dark"]`；
2. 核心语义类（`.page-header`、`.card-wrapper`、`.description-item-*`、`.table` 等）加 `!important`；
3. 新增 `.menu-item-title.active`、`.empty-title`、`.alert-wrapper` 覆盖；
4. 新增 `[class*="uno-"]` 兜底三件套；
5. 修正根背景规则，让 `html` 本身也参与暗色。

### P1（按插件逐个补齐并复扫）

6. `ah-*`、`feed-*`、私密文章、AI 评论插件语义类覆盖；
7. Monaco 主题切换接入；
8. 数据工坊、代码注入器、Meilisearch、导入/存储工具等 `uno-*` 页面复查。

### P2（清理）

9. 删除失效的 Vuetify 类规则，收敛宽泛匹配；
10. 统一链接色规则，消除重复/冲突。

## 六、完整残留明细

见 `workplace/aggregate.txt`（134 组，含影响页面列表），原始数据见 `workplace/scan-results.json`。
