panatgithub_AnkiHeadingSync/docs/settings-sticky-overlap-decisions.md
Dusk c1dbddd9c0 docs: add sticky overlap fix and header docking documentation
docs:添加吸顶重叠修复和页头停靠文档
2026-04-25 21:21:33 +08:00

3.5 KiB
Raw Blame History

设置页 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”结构。