Files
shanxia2.0/docs/superpowers/specs/2026-09-12-miniprogram-header-capsule-safe-area-design.md
T

120 lines
7.2 KiB
Markdown
Raw 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.
# 小程序自定义顶部栏 · 微信胶囊安全区适配(方案 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-*` 变量。