触发条件

  • 全站顶栏用 position: sticky 放在文档流顶部,占位但参与 100vh 计算。
  • 工具页想做一个"占满剩余视口"的编辑器布局,body 写 height: calc(100vh - 44px),44px 是顶栏高度。
  • 页面本身 <html> 缺 class="dark" 且内联样式写死亮色底,白边在亮底上格外刺眼。

症状

  • 编辑器整体差一条顶栏高度的空隙没填满视口,底部露出 html 默认白底。
  • 用户描述为"没有全屏",注意力集中在"是不是 iframe 嵌入"之类集成方式上。
  • 外层可能出现多余滚动条或页面整体偏短。

容易误判的方向

  • 怀疑接入方式(iframe / 动态加载)——实际整页直出,与集成无关。
  • 只顾修暗色主题:补 class="dark"、换掉写死的亮色背景,视觉上"白边变黑边"但没有填满,问题只解决一半。
  • 不用 DevTools 量尺寸,凭截图猜原因。真实根因(861 ≠ 905)一量便知。

根因

sticky 定位的元素仍在文档流内,其 44px 高度本来就占据 100vh 的一部分。calc(100vh - 44px) 等于把顶栏高度扣了两次:

44 (顶栏) + calc(100vh - 44px) (body) = 100vh + 44 → 不对,实际渲染为
44 (顶栏在流内) + 861 (body) = 905 = 100vh,body 本应 905

即 body 被压短 44px,flex 布局的工作区 flex: 1 跟着变矮,底部露出 html 白底。

关键区别:position: fixed 的顶栏脱离文档流,才需要 calc(100vh - 44px) 或 padding 补偿;sticky 顶栏不需要,height: 100vh + flex 即可。

最终解决原则

  1. 先用 CDP/DevTools 量几何数据定位:innerHeight vs getBoundingClientRect() 的 body/workspace 高度,差值直接指向来源。
  2. sticky 顶栏场景:body 用 height: 100vh; display: flex; flex-direction: column; overflow: hidden,主区 flex: 1 自动填满剩余空间,不手写任何 px 补偿。
  3. fixed 顶栏才需要补偿(padding-top 或 calc),二者机制不同不能照抄。
  4. 同款错误要全局 grep:100vh - <topbar高度> 在页面主体、导出模板、弹层里可能各出现一次,逐一核对上下文中顶栏是否真的脱流。
  5. 编辑器类页面(A4 纸、画布)的三类颜色区域要区分:编辑器 UI 跟随主题、内容纸张保持白色(打印语义)、导出模板字符串是独立世界。
  6. <html> 的 class="dark" 是全站主题命名空间,独立设计页也要记得补。

验证方法

  • 无头浏览器 CDP Runtime.evaluate 断言:innerHeight =<mark> document.documentElement.scrollHeight、画布容器 bottom 与视口底零间隙、window.scrollY </mark>= 0 无外层滚动。
  • Page.captureScreenshot 截图核对底部边缘。
  • 改动后再跑一遍打印/导出路径(@media print、html2canvas、导出模板)确认未波及。

识别口诀

页面差一条顶栏高的白边,先问顶栏是 sticky 还是 fixed:sticky 在流内不要再减,fixed 脱流才要 calc 补。量几何,别猜主题。

相关概念

  • CSS sticky 定位与文档流 (CSS sticky Positioning and Document Flow)
  • 独立编辑器页脱离全站暗色主题 (Standalone Editor Page Missing Site Dark Theme)

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Frontend