158 lines
8.4 KiB
Markdown
158 lines
8.4 KiB
Markdown
# 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`。
|