From 2866fef5bf35f6c88e158aad3fa625c2a4420636 Mon Sep 17 00:00:00 2001 From: wuzilong <704541015@qq.com> Date: Sat, 12 Sep 2026 18:45:39 +0800 Subject: [PATCH] docs: add miniprogram header capsule safe-area design (scheme B). Co-authored-by: Cursor --- ...program-header-capsule-safe-area-design.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-12-miniprogram-header-capsule-safe-area-design.md diff --git a/docs/superpowers/specs/2026-09-12-miniprogram-header-capsule-safe-area-design.md b/docs/superpowers/specs/2026-09-12-miniprogram-header-capsule-safe-area-design.md new file mode 100644 index 000000000..e67831ab0 --- /dev/null +++ b/docs/superpowers/specs/2026-09-12-miniprogram-header-capsule-safe-area-design.md @@ -0,0 +1,119 @@ +# 小程序自定义顶部栏 · 微信胶囊安全区适配(方案 B) + +> 日期:2026-09-12 +> 范围:`miniprogram` 中 `navigationStyle: custom` 的页面 +> 状态:待用户审阅后进入实现计划 + +## 1. 背景与问题 + +体验版中,从工作台进入地磅「仪表盘」等自定义导航页时,业务顶部栏(返回、标题、右侧用户名/操作)与微信小程序原生顶栏(状态栏 + 右上角胶囊「··· / 关闭」)重叠,尤其右侧关闭按钮区域会挡住业务内容。 + +根因: + +1. 多数业务顶栏仅用固定 `padding`(如 `.db-header { padding: 12px 16px }`),未计入 `statusBarHeight`。 +2. 仓库已有 `utils/safeArea.js`、`components/app-safe-header.vue` 与 CSS 变量约定(`--sq-safe-top` 等),但: + - `applySafeAreaCssVars` 仅写入 H5 的 `document.documentElement`,**微信小程序端不生效**; + - `app-safe-header` **未被任何页面引用**; + - 地磅 `.db-header`、报销 `.topbar`、壳层 `.mp-header` 未统一消费同一套量纲。 + +用户确认采用 **方案 B**:顶部加高并对齐胶囊垂直中心,**右侧永久预留胶囊宽度**,业务可点按钮不得放入胶囊区。 + +## 2. 目标 + +- 所有自定义导航页的顶栏内容(标题、返回、次要文案)落在胶囊下方/左侧安全区内,不被遮挡。 +- 量纲由运行时 API 计算,适配不同机型(刘海、胶囊位置差异)。 +- 视觉风格不变:白底列表顶栏与绿色渐变大头仍分别沿用现有 Token;只调整几何与占位。 +- 最小改动:复用已有 `safeArea` 基建,统一样式入口,避免每页手写高度。 + +## 3. 非目标 + +- 不改系统默认导航栏页面(如协议/隐私等非 custom 页)。 +- 不调整底部 TabBar / `safe-area-inset-bottom`(除非顺带发现明显缺陷且与本次无关则不做)。 +- 不做顶栏视觉重设计(颜色、圆角、字号大改)。 +- 不在右侧胶囊区放置业务「关闭」「更多」按钮。 + +## 4. 量纲与 CSS 变量 + +沿用并落实 `miniprogram/utils/safeArea.js` 的计算(`uni.getSystemInfoSync` + `uni.getMenuButtonBoundingClientRect`): + +| 变量 | 含义 | 典型算法 | +|------|------|----------| +| `--sq-safe-top` | 状态栏高度 | `statusBarHeight` | +| `--sq-nav-height` | 导航内容行高(与胶囊垂直居中) | `(capsule.top - statusBarHeight) * 2 + capsule.height`,下限 44 | +| `--sq-header-height` | 顶栏总高 | `safe-top + nav-height` | +| `--sq-capsule-right-safe` | 右侧预留宽 | `capsule.width + (windowWidth - capsule.right) + 水平余量`,无胶囊时为 `0` | + +启动时 `App.onLaunch` 已调用 `initGlobalSafeArea()`;实现时须保证指标写入 **小程序可消费的样式**(见 §5),不能仅依赖 H5 `document`。 + +## 5. 布局规则(方案 B) + +### 5.1 白底顶栏(地磅 / 报销) + +结构: + +``` +┌─────────────────────────────────────────────┐ +│ 状态栏占位 (--sq-safe-top) │ +├──────────┬──────────────────┬───────────────┤ +│ 返回+标题 │ 次要信息(可选) │ 胶囊右侧空白 │ +│ │ │ (不可放按钮) │ +└──────────┴──────────────────┴───────────────┘ + ←────────── --sq-nav-height ───────────────→ +``` + +约束: + +1. 总高度 = `--sq-header-height`;内容行垂直居中对齐胶囊。 +2. 网格或等价布局:`auto | minmax(0,1fr) | var(--sq-capsule-right-safe)`。 +3. 标题省略号截断;右侧列为空占位。 + +### 5.2 渐变大头(工作台 / 首页 / 待办等 `.mp-header`) + +- `padding-top`: `calc(var(--sq-safe-top) + 内容上边距)`(替换仅 `env(safe-area-inset-top)` 或写死像素)。 +- `padding-right`: `calc(水平内边距 + var(--sq-capsule-right-safe))`,保证副文案/用户信息不进入胶囊区。 +- 若该页在头部右侧放置「退出」等按钮:须落在胶囊左侧列,不得占用 `--sq-capsule-right-safe` 区域(工作台现有右侧用户栈需按此收紧)。 + +### 5.3 变量下发(微信端)— 既定路径 + +采用 **「SCSS 统一吃变量 + 顶栏根节点内联注入」**,不强制先改完所有页面 DOM: + +1. 新增或复用 composable / 工具函数:基于 `getGlobalSafeArea()` 返回四变量的 style 对象(px 字符串)。 +2. `.db-header` / `.bx-page .topbar` / `.mp-header`(及必要变体)在 SCSS 中改用 `--sq-*`;各页顶栏根节点绑定 `:style="safeAreaStyle"`(或等价)。 +3. `app-safe-header`:补齐样式与插槽后,**新页优先使用**;存量地磅/报销可先改 SCSS + 内联变量,不必一次性替换 DOM。 +4. `applySafeAreaCssVars`:保留 H5 写入 `document`;微信端以顶栏内联为准(不依赖 page 全局 CSS 变量穿透)。 + +禁止:仅增大固定 `padding-top`、不预留右侧(已否决的方案 C)。 + +## 6. 影响面 + +| 样式/组件 | 路径 | 动作 | +|-----------|------|------| +| safeArea 工具 | `miniprogram/utils/safeArea.js` | 确保微信端可消费;必要时补小程序注入 | +| 公共顶栏 | `miniprogram/components/app-safe-header.vue` | 完善后供白底页复用,或抽出等效 SCSS | +| 地磅顶栏 | `miniprogram/styles/db-theme.scss` + 各地磅页 | `.db-header` 改为方案 B 几何 | +| 报销顶栏 | `miniprogram/styles/bx-theme.scss` | `.topbar` 对齐同一变量(替换仅 `env(safe-area-inset-top)` + 写死 58px) | +| 壳层大头 | `miniprogram/styles/mp-shell.scss`(及 `mp-biz` 变体) | `.mp-header*` 使用 safe-top + capsule-right | +| 既有大背景头 | `miniprogram/styles/index.scss` `.sq-hero-header` | 核对已引用变量是否在微信端生效;无效则一并修通 | +| UI 规范 | `docs/miniprogram-ui-spec-sanqiang.md` §3.2 | 补充「自定义 Header 须适配胶囊」SHALL | + +页面枚举以 `pages.json` 中 `navigationStyle: custom` 为准,至少覆盖:工作台、首页、待办、地磅全链路、报销全链路、占位页。 + +## 7. 验收标准 + +1. iPhone(刘海)与 Android 体验版:仪表盘返回/标题/用户名均不被胶囊遮挡。 +2. 地磅列表/详情、报销列表/表单顶栏同样不被遮挡。 +3. 工作台渐变头标题与右侧用户/退出不与胶囊重叠。 +4. H5 预览不出现异常巨大右侧空白或顶栏塌陷(无胶囊时 `--sq-capsule-right-safe = 0`)。 +5. 不引入新的业务按钮挤进胶囊区。 + +## 8. 风险与注意 + +- `getMenuButtonBoundingClientRect` 在部分端或过早调用可能为空:已有默认值(safe-top≈20、nav=44、右侧 0/96);实现时保持兜底。 +- 工作台当前 `mp-header--workbench` 含额外 `40px` 偏移,改造时应用变量替换魔法数,避免双重叠加导致头部过高。 +- 规范文档与 Demo HTML 可后置同步,但代码合入前至少更新 `miniprogram-ui-spec-sanqiang.md` 中 Header 一小节。 + +## 9. 决策记录 + +- **方案 B**(加高 + 右侧预留)— 用户确认 2026-09-12。 +- **否决方案 C**(只加高不预留右侧)。 +- 视觉 Token 不换色;几何统一到 `--sq-*` 变量。