mirror of
https://github.com/panatgithub/AnkiHeadingSync.git
synced 2026-07-22 06:51:43 +00:00
docs: add sticky overlap fix and header docking documentation
docs:添加吸顶重叠修复和页头停靠文档
This commit is contained in:
parent
0d0f04aba2
commit
c1dbddd9c0
2 changed files with 194 additions and 0 deletions
97
docs/settings-sticky-overlap-decisions.md
Normal file
97
docs/settings-sticky-overlap-decisions.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# 设置页 Sticky 遮挡修复决策
|
||||
|
||||
本文锁定本轮“页面标题遮罩 + 卡片标题停靠”修复的最终实现策略。
|
||||
|
||||
## 1. 页面标题仍是最高层 sticky
|
||||
|
||||
- 保留 `display()` 中的 `pageHeaderEl`。
|
||||
- 最终样式决策:
|
||||
- `position: sticky`
|
||||
- `top: 0px`
|
||||
- `zIndex: 300`
|
||||
- `backgroundColor: var(--modal-background, var(--background-primary))`
|
||||
- 继续保留现有 inline style 方式,不新增全局样式表。
|
||||
|
||||
原因:
|
||||
|
||||
- 当前仓库设置页布局主要仍由 inline style 负责。
|
||||
- 页面标题是统一的上层遮挡面,应该高于所有卡片标题。
|
||||
|
||||
## 2. 页面标题增加独立 mask,而不是只依赖 header 本体背景
|
||||
|
||||
- 在 `pageHeaderEl` 内增加:
|
||||
- `data-settings-page-header-mask="true"`
|
||||
- mask 使用:
|
||||
- `position: absolute`
|
||||
- 向上扩展
|
||||
- 向左右扩展
|
||||
- 与页面标题相同的不透明主题背景
|
||||
- mask 层级低于标题文本,但跟随页面标题一起处于最高层 sticky 堆叠上下文。
|
||||
|
||||
原因:
|
||||
|
||||
- 仅靠 `pageHeaderEl` 自身背景,只能覆盖 header 盒子范围,无法盖住页面标题上方和左右的透明缺口。
|
||||
|
||||
## 3. 卡片标题恢复 sticky,但固定停在页面标题下方
|
||||
|
||||
- `settingsCardToggle` 最终样式决策:
|
||||
- `position: sticky`
|
||||
- `top: var(--ahs-settings-page-header-height, 64px)`
|
||||
- `zIndex: 200`
|
||||
- `backgroundColor: var(--modal-background, var(--background-primary))`
|
||||
- 保留现有按钮视觉:
|
||||
- `width: 100%`
|
||||
- `border: 2px solid var(--background-modifier-border)`
|
||||
- `fontSize: 1.5em`
|
||||
- 点击切换折叠/展开
|
||||
|
||||
原因:
|
||||
|
||||
- 卡片标题需要 sticky,才能满足“滚动到页面标题下方后停住”的交互。
|
||||
- `top` 必须基于页面标题真实高度,不能再写死为 `0`。
|
||||
- `zIndex` 必须低于页面标题层级,避免钻到标题前面。
|
||||
|
||||
## 4. 页面标题高度通过 CSS 变量驱动
|
||||
|
||||
- 在 `containerEl` 上写入:
|
||||
- `--ahs-settings-page-header-height`
|
||||
- 默认值:
|
||||
- `64px`
|
||||
- 运行时优先用 `ResizeObserver` 监听 `pageHeaderEl`。
|
||||
- 如可测量,则通过 `getBoundingClientRect()` 取真实高度并回写像素值。
|
||||
- 无法测量时保留 `64px` fallback。
|
||||
|
||||
原因:
|
||||
|
||||
- 测试环境和部分渲染阶段无法可靠给出布局尺寸,需要一个稳定 fallback。
|
||||
- 真实 Obsidian 设置页中,标题高度可能受字体或缩放影响,运行时测量更稳妥。
|
||||
|
||||
## 5. `hide()` 负责 observer 清理
|
||||
|
||||
- 在 `hide()` 中断开页面标题高度 observer。
|
||||
- 同时清掉存储的 observer 引用,避免重复打开设置页时累积监听。
|
||||
|
||||
原因:
|
||||
|
||||
- `displayInitialized` 会在 `hide()` 后复位,下一次打开会重建 DOM。
|
||||
- 如果不清理 observer,会造成重复观察和不可预测的高度回写。
|
||||
|
||||
## 6. 保持不变的边界
|
||||
|
||||
- 不改 `pageHeaderEl / settingsCardsContainer / cardEl / headerEl / bodyEl` 这一卡片 shell 结构。
|
||||
- 不改 `toggleCard()` 的展开/折叠逻辑。
|
||||
- 不改 `renderCard()` 的局部刷新边界。
|
||||
- 不改同步逻辑、设置数据结构、命令行为。
|
||||
- 不引入:
|
||||
- scroll listener
|
||||
- `IntersectionObserver`
|
||||
- `requestAnimationFrame` 滚动逻辑
|
||||
|
||||
## 7. 与旧 sticky 文档的偏离说明
|
||||
|
||||
- 仓库里已有的旧文档把卡片标题视为 static,这是之前一次实现决策。
|
||||
- 本轮按新的用户合同执行,原因是当前真实 UI 目标已经变化:
|
||||
- 页面标题需要继续 sticky 并补齐遮罩
|
||||
- 卡片标题也需要 sticky,但停靠在页面标题下方
|
||||
|
||||
因此,本轮不是延续旧方案,而是在同一真实代码接点上升级为“两层 sticky”结构。
|
||||
97
docs/settings-sticky-overlap-gap-report.md
Normal file
97
docs/settings-sticky-overlap-gap-report.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# 设置页 Sticky 遮挡差距审计
|
||||
|
||||
本文基于当前仓库真实实现,定位设置页顶部透视与卡片标题停靠异常的实际接入点。
|
||||
|
||||
## 1. 当前 `display()` 已有页面级 sticky header,但遮罩不完整
|
||||
|
||||
- 入口在 [src/presentation/settings/PluginSettingTab.ts](src/presentation/settings/PluginSettingTab.ts)。
|
||||
- `display()` 首次渲染时已经创建了 `pageHeaderEl`,并设置了:
|
||||
- `position: sticky`
|
||||
- `top: 0`
|
||||
- `zIndex: 100`
|
||||
- `background: var(--background-primary)`
|
||||
- 但当前 `pageHeaderEl` 只有自身盒子背景,没有任何向上、向左右扩展的遮罩层。
|
||||
|
||||
结果是:页面标题本身能 sticky,但上方和侧边留白区域仍可能透出下层设置内容,尤其在 Obsidian 设置容器滚动时更明显。
|
||||
|
||||
## 2. 当前卡片标题按钮是 static,不会停靠在页面标题下方
|
||||
|
||||
- `initializeCards()` 中五张卡片仍是统一 shell:
|
||||
|
||||
```text
|
||||
pageHeaderEl
|
||||
settingsCardsContainer
|
||||
cardEl
|
||||
headerEl(button)
|
||||
bodyEl(div)
|
||||
```
|
||||
|
||||
- `settingsCardToggle` 当前只保留普通按钮样式:
|
||||
- `display: flex`
|
||||
- `width: 100%`
|
||||
- `fontSize: 1.5em`
|
||||
- `background: var(--background-primary)`
|
||||
- `border: 2px solid var(--background-modifier-border)`
|
||||
- 没有:
|
||||
- `position: sticky`
|
||||
- `top`
|
||||
- `zIndex`
|
||||
|
||||
结果是:卡片标题不会在滚动到页面顶栏下方时停住,因此无法实现“卡片标题栏顶到 Anki Heading Sync 下方后停止”的设计目标。
|
||||
|
||||
## 3. 当前没有页面标题高度变量,也没有测量逻辑
|
||||
|
||||
- `containerEl` 当前没有写入 `--ahs-settings-page-header-height`。
|
||||
- `PluginSettingTab` 当前没有:
|
||||
- `ResizeObserver`
|
||||
- `getBoundingClientRect()` 回退测量
|
||||
- 页面标题高度的状态同步
|
||||
|
||||
结果是:即使恢复卡片标题 sticky,也没有可靠的 `top` 偏移来源,卡片标题无法稳定停靠在页面标题栏下方。
|
||||
|
||||
## 4. 当前 `hide()` 不做页面标题测量清理
|
||||
|
||||
- `hide()` 当前只做:
|
||||
- `displayInitialized = false`
|
||||
- `cardShells.clear()`
|
||||
- debounce 和缓存状态清理
|
||||
- 没有任何 observer 断开逻辑。
|
||||
|
||||
如果本轮引入页面标题高度观察器,必须在 `hide()` 中断开,避免设置页重复打开后残留多重监听。
|
||||
|
||||
## 5. 现有展开/折叠与局部刷新接点应保持不变
|
||||
|
||||
- `toggleCard()` 只维护 `expandedCardIds`。
|
||||
- `renderCard()` 只更新单卡:
|
||||
- 标题文本
|
||||
- `aria-expanded`
|
||||
- `bodyEl.style.display`
|
||||
- `bodyEl.empty()` 后重绘
|
||||
- 已有测试也覆盖了:
|
||||
- 折叠展开不整页重建
|
||||
- 卡片 1 局部刷新不整页重建
|
||||
|
||||
这部分已经是正确的局部刷新边界,本轮不应改动。
|
||||
|
||||
## 6. 父容器路径上未发现必须先处理的 sticky 阻断样式
|
||||
|
||||
- 当前拥有 sticky 行为的直接元素只有页面级 `pageHeaderEl`。
|
||||
- 在 `PluginSettingTab.ts` 的设置页装配路径中,未发现 `settingsCardsContainer`、`cardEl`、`bodyEl` 上存在会直接阻断标题按钮 sticky 的 `overflow: hidden/auto` 接入点。
|
||||
|
||||
因此本轮优先按用户合同落两层 sticky,并通过最小增量验证真实行为;不额外引入滚动监听或观察滚动位置的 JS 逻辑。
|
||||
|
||||
## 7. 结论
|
||||
|
||||
当前仓库与本轮目标之间的真实差距是:
|
||||
|
||||
1. 页面级 sticky 标题栏已有,但缺少完整不透明遮罩。
|
||||
2. 卡片标题栏当前是 static,无法停靠在页面标题栏下方。
|
||||
3. 缺少页面标题高度 CSS 变量和测量更新逻辑。
|
||||
4. `hide()` 缺少 observer 清理。
|
||||
|
||||
最小且符合仓库现状的修复路径是:
|
||||
|
||||
1. 保留 `pageHeaderEl` 作为最高层 sticky header,并补一层绝对定位 mask。
|
||||
2. 在 `containerEl` 上写入 `--ahs-settings-page-header-height`,默认 `64px`,运行时按真实高度更新。
|
||||
3. 让每个 `settingsCardToggle` 恢复 sticky,并使用页面标题高度变量作为 `top`。
|
||||
4. 在 `hide()` 中断开页面标题高度 observer。
|
||||
Loading…
Reference in a new issue