panatgithub_AnkiHeadingSync/docs/settings-card-sticky-header-gap-report.md
Dusk 33a4d29c4d fix(settings): 固定页面级标题栏 / pin page-level settings header
中文: 将设置页顶部标题改为页面级 sticky 白色标题栏,并取消每个卡片标题的 sticky,修复滚动遮挡、正文重叠和边框异常。

English: Convert the settings page title into a page-level sticky white header and remove sticky behavior from section headers to fix scroll overlap, body occlusion, and border artifacts.
2026-04-25 18:33:58 +08:00

99 lines
No EOL
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 设置页 Sticky 标题栏差距审计
本文基于当前仓库真实实现,审计“设置页顶部白色标题栏固定显示”的正确接入点,以及之前方案为什么会导致遮挡异常。
## 1. 当前真实问题不在卡片内部,而在页面顶部缺少 sticky 标题栏
- 入口仍在 [src/presentation/settings/PluginSettingTab.ts](src/presentation/settings/PluginSettingTab.ts)。
- `display()` 首次进入时,原先只创建了一个普通 `h2`
- `containerEl.createEl("h2", { text: t("settings.pluginTitle") })`
- 这个 `h2` 不 sticky也不是单独的遮挡层。
结果是:设置页真正缺少的是页面级顶部白色标题区域,而不是卡片级 sticky header。
## 2. 之前错误方案把 sticky 放到了每个设置卡片标题上
- `initializeCards()` 里,原先对每个 `settingsCardToggle` 设置了:
- `position: sticky`
- `top: 0`
-`z-index`
- 每个卡片标题仍然是交互按钮,同时承担 sticky、边框、背景、遮挡等职责。
这会导致两个问题:
1. 多个 section header 在同一滚动上下文里争抢顶部位置。
2. 卡片标题压住正文,出现边框、留白和叠层异常。
## 3. 当前卡片壳层逻辑本来就不需要卡片标题 sticky
- 当前五张卡片仍然是统一 card shell
```text
cardEl
headerEl(button)
bodyEl(div)
```
- `toggleCard()` 负责折叠/展开。
- `renderCard()` 负责:
- 更新 header 文本
- 更新 `aria-expanded`
- 切换 `bodyEl.style.display`
- 清空并重绘 body
- 局部刷新仍然基于 `renderCard(cardId)`,而不是整页重建。
这说明卡片标题只需要保持“普通标题按钮”职责,不应该再兼任 sticky 遮挡层。
## 4. 正确 sticky 层级应该是页面级 header而不是 section header
- 用户真实想要的效果是:
- 最顶部的 “Anki Heading Sync” 始终固定显示
- 它作为白色背景遮挡层,阻止下面内容跑到页面最上方
- 卡片标题本身正常滚动,不再吸附
- 因此正确结构应是:
```text
containerEl
pageHeaderEl(sticky)
h2
cardsContainerEl
cardEl
headerEl(button, static)
bodyEl
```
## 5. 当前仓库仍然适合用 inline style而不是新增样式表
- 仓库当前没有 `styles.css`
- [PluginSettingTab.ts](src/presentation/settings/PluginSettingTab.ts) 现有布局样式仍然主要是 inline style。
因此页面级 sticky header 仍应直接在 `display()` 初始化时落 inline style与仓库现状一致。
## 6. 当前没有证据表明需要 JS 滚动逻辑
- 没有现成的 `scroll` listener、`IntersectionObserver` 或 `requestAnimationFrame` 滚动同步逻辑。
- 页面级 sticky header 已经满足需求,不需要 JS fallback。
## 7. 之前测试锚点也验证了错误方向
- [src/presentation/settings/PluginSettingTab.test.ts](src/presentation/settings/PluginSettingTab.test.ts) 之前断言的是:
- 每个 `settingsCardToggle` 都是 sticky
- 这与用户真实目标冲突。
正确测试应该改成:
1. 存在页面级 `settingsPageHeader`
2. `settingsPageHeader` 是 sticky。
3. 每个 `settingsCardToggle` 不再 sticky。
4. 每个 `settingsCardToggle` 仍保留标题按钮视觉样式。
## 8. 结论
当前仓库的真实差距不是“section header sticky 还不够强”,而是“页面级标题栏本来就没有 sticky”。
最小、安全、符合真实需求的修复路径是:
1.`display()` 中创建单独的 `settingsPageHeader` 容器并设为 sticky。
2. 将原来的 `h2` 放入该 header 容器。
3. 将卡片列表放到单独的 cards container 下方。
4. 取消每个 `settingsCardToggle` 的 sticky只保留普通标题条样式。