346 lines
12 KiB
Markdown
346 lines
12 KiB
Markdown
# 间距测量与 rpx 换算
|
||
|
||
## 核心换算公式
|
||
|
||
```
|
||
小程序 viewport 宽 = 750rpx = 430px
|
||
RPX_FACTOR = 750 / 430 = 1.7442
|
||
|
||
精确公式:rpx = ceil(H5_px × 1.7442 / 2) × 2
|
||
简化心算:rpx ≈ H5_px × 2 × 0.875 取偶(6px、14px 处有 2rpx 偏差,以精确公式为准)
|
||
|
||
圆角例外:border-radius = px × 2(不乘系数),数值更整洁
|
||
```
|
||
|
||
---
|
||
|
||
## 结构化审计方法论(三阶段)
|
||
|
||
本方法论适用于两个场景:
|
||
- **迁移前**:对 H5 页面做详细审计,产出映射表,指导 MP 开发
|
||
- **迁移后**:基于映射表做双端对比,逐元素验证偏差
|
||
|
||
### 阶段 0:结构拆解(自顶向下)
|
||
|
||
目标:将页面拆解为树状元素清单,建立 H5↔MP 映射表。
|
||
|
||
#### 0.1 拆解流程
|
||
|
||
1. 读取 H5 源码(`docs/h5_ui/pages/<page>.html`),识别页面首层容器
|
||
2. 对每个首层容器,递归拆解子元素,直到到达叶子节点
|
||
3. 叶子节点定义:**单一样式属性可描述**的最小视觉单元
|
||
- 文字 span(font-size + color + weight 即可描述)
|
||
- 图标 image / SVG
|
||
- 纯色/渐变 view(background 即可描述)
|
||
- 分隔线(border 即可描述)
|
||
4. 为每个节点记录:层级深度、CSS 选择器、Tailwind 类名、角色描述
|
||
|
||
#### 0.2 H5 审计映射表(迁移前必做)
|
||
|
||
拆解完成后,产出结构化映射表。此表是后续所有工作的基准:
|
||
|
||
```markdown
|
||
## <page> H5 审计映射表
|
||
|
||
| # | 层级 | 元素描述 | H5 选择器 | Tailwind 类名 | 理论 rpx 值 | MP 选择器 | 备注 |
|
||
|---|------|---------|-----------|--------------|------------|-----------|------|
|
||
| 1 | L0 | 页面根容器 | .page | px-4 bg-gray-1 | padding: 0 14rpx | .page | — |
|
||
| 2 | L1 | Banner 区域 | .banner-bg | h-40 rounded-2xl | height: 140rpx, radius: 32rpx | .banner-bg | 渐变需简化 |
|
||
| 3 | L1 | 统计卡片 | .summary-card | p-4 rounded-xl | padding: 28rpx, radius: 24rpx | .summary-card | — |
|
||
| 4 | L2 | 卡片标题 | .summary-card h3 | text-base font-semibold | font-size: 28rpx, weight: 600 | .card-title | — |
|
||
| 5 | L2 | 金额数值 | .amount | text-2xl font-semibold | font-size: 42rpx, weight: 600 | .amount | — |
|
||
| ... | ... | ... | ... | ... | ... | ... | ... |
|
||
```
|
||
|
||
列说明:
|
||
- **层级**:L0=页面根, L1=首层区块, L2=区块内组件, L3=组件内元素...
|
||
- **理论 rpx 值**:从 Tailwind 类名查速查表换算,不是实测值
|
||
- **MP 选择器**:迁移前留空,迁移后填入对应的 WXML 选择器
|
||
- **备注**:CSS 风险特性、不可消除差异、特殊处理方案
|
||
|
||
#### 0.3 结构完整性校验
|
||
|
||
映射表同时用于校验 MP 端结构完整性:
|
||
|
||
| 校验项 | 方法 | 判定 |
|
||
|--------|------|------|
|
||
| 元素缺失 | H5 映射表中有、MP 选择器为空或不存在 | P0 |
|
||
| 元素多余 | MP 中存在映射表未列出的视觉元素 | 检查是否为调试元素,否则标注 |
|
||
| 顺序错误 | MP 元素 DOM 顺序与映射表不一致 | P0 |
|
||
| 嵌套层级不一致 | MP 的父子关系与 H5 不同 | P1(可能影响间距计算) |
|
||
|
||
校验时机:
|
||
- **迁移前**:映射表产出后,MP 选择器列全部留空,无需校验
|
||
- **迁移后**:填入 MP 选择器,逐行校验存在性和顺序
|
||
- **对比审计时**:先跑结构完整性校验,通过后再进入测量阶段
|
||
|
||
|
||
### 阶段 1:逐级测量(自底向上)
|
||
|
||
目标:从叶子节点开始,逐级向上测量每个元素的尺寸和间距。
|
||
|
||
#### 1.1 测量顺序
|
||
|
||
```
|
||
叶子节点(L3/L4)→ 组件容器(L2)→ 区块容器(L1)→ 页面根(L0)
|
||
```
|
||
|
||
自底向上的原因:内层元素的实测尺寸决定了外层容器的实际高度。先测内层,才能判断外层的 padding/gap 是否正确。
|
||
|
||
#### 1.2 每个元素的标准测量维度
|
||
|
||
| 维度 | 测量方法 | 适用节点 |
|
||
|------|---------|---------|
|
||
| width / height | `getBoundingClientRect()` | 所有 |
|
||
| padding(四方向) | `getComputedStyle().paddingTop/Right/Bottom/Left` | 容器节点 |
|
||
| margin(四方向) | `getComputedStyle().marginTop/Right/Bottom/Left` | 所有 |
|
||
| font-size | `getComputedStyle().fontSize` | 文字节点 |
|
||
| line-height | `getComputedStyle().lineHeight` | 文字节点 |
|
||
| border-radius | `getComputedStyle().borderRadius` | 有圆角的节点 |
|
||
| 与父容器的 offset | `child.rect.top - parent.rect.top - parent.paddingTop` | 所有子节点 |
|
||
| 与相邻兄弟的 gap | `next.rect.top - current.rect.bottom` | 同级相邻节点 |
|
||
|
||
#### 1.3 H5 端测量(Playwright MCP / measure_gaps.py)
|
||
|
||
方式 A:Playwright MCP `browser_evaluate`
|
||
|
||
```javascript
|
||
// 测量单个元素的完整属性
|
||
async (selector) => {
|
||
const el = document.querySelector(selector);
|
||
if (!el) return { error: 'not found' };
|
||
const rect = el.getBoundingClientRect();
|
||
const cs = getComputedStyle(el);
|
||
return {
|
||
selector,
|
||
width: rect.width, height: rect.height,
|
||
top: rect.top, left: rect.left,
|
||
paddingTop: parseFloat(cs.paddingTop),
|
||
paddingRight: parseFloat(cs.paddingRight),
|
||
paddingBottom: parseFloat(cs.paddingBottom),
|
||
paddingLeft: parseFloat(cs.paddingLeft),
|
||
marginTop: parseFloat(cs.marginTop),
|
||
marginBottom: parseFloat(cs.marginBottom),
|
||
fontSize: parseFloat(cs.fontSize),
|
||
lineHeight: cs.lineHeight === 'normal' ? 'normal' : parseFloat(cs.lineHeight),
|
||
fontWeight: cs.fontWeight,
|
||
borderRadius: cs.borderRadius,
|
||
color: cs.color,
|
||
backgroundColor: cs.backgroundColor
|
||
};
|
||
}
|
||
```
|
||
|
||
> Playwright MCP 不支持 `file://` 协议。需先起本地 HTTP 服务:
|
||
> `python -m http.server 8765 --directory docs/h5_ui/pages`
|
||
> 然后用 `browser_navigate("http://localhost:8765/<page>.html")` 访问。
|
||
|
||
方式 B:`scripts/ops/measure_gaps.py`(批量测量)
|
||
|
||
```bash
|
||
uv run python scripts/ops/measure_gaps.py <page> --selectors "<sel1>" "<sel2>" ...
|
||
```
|
||
|
||
#### 1.4 MP 端测量(SelectorQuery)
|
||
|
||
```javascript
|
||
// 微信开发者工具 MCP evaluate_script
|
||
async (selector) => {
|
||
return new Promise(resolve => {
|
||
const query = wx.createSelectorQuery();
|
||
query.select(selector).boundingClientRect(rect => {
|
||
query.select(selector).fields({
|
||
computedStyle: ['paddingTop','paddingRight','paddingBottom','paddingLeft',
|
||
'marginTop','marginBottom','fontSize','lineHeight',
|
||
'fontWeight','borderRadius','color','backgroundColor']
|
||
}, style => {
|
||
resolve({ rect, style });
|
||
}).exec();
|
||
}).exec();
|
||
});
|
||
}
|
||
```
|
||
|
||
#### 1.5 测量结果记录格式
|
||
|
||
每个元素的测量结果追加到映射表:
|
||
|
||
```markdown
|
||
| # | 元素 | 属性 | H5 实测(px) | 理论 rpx | MP 实测(rpx) | 偏差 | 级别 |
|
||
|---|------|------|------------|---------|-------------|------|------|
|
||
| 4 | 卡片标题 | font-size | 16px | 28rpx | 28rpx | 0 | ✅ |
|
||
| 4 | 卡片标题 | line-height | 24px | 42rpx | 36rpx | -6rpx | P3 |
|
||
| 4 | 卡片标题 | font-weight | 600 | 600 | 400 | — | P6 |
|
||
| 3 | 统计卡片 | padding-top | 16px | 28rpx | 30rpx | +2rpx | ✅ |
|
||
| 3→4 | 卡片→标题 gap | margin-top | 0px | 0rpx | 0rpx | 0 | ✅ |
|
||
```
|
||
|
||
|
||
### 阶段 2:偏差审计
|
||
|
||
目标:基于测量结果,逐属性判定偏差级别,输出结构化审计报告。
|
||
|
||
#### 2.1 偏差判定标准
|
||
|
||
| rpx 偏差 | 级别 | 说明 |
|
||
|----------|------|------|
|
||
| 0 | ✅ 通过 | 完全匹配 |
|
||
| ≤ 2rpx | ✅ 通过 | rpx 取偶导致的不可避免误差 |
|
||
| > 2rpx 且 ≤ 4rpx | ⚠️ 警告(P4-P7) | 像素级精调可修复 |
|
||
| > 4rpx | ❌ 不通过(P0-P3) | 必须修正 |
|
||
|
||
特殊属性判定:
|
||
- **font-weight**:不用 rpx 偏差,直接比对数值(400/500/600/700),不一致即 P6
|
||
- **color**:不用 rpx 偏差,比对 hex 值,不在标准色表中即 P5
|
||
- **border-radius**:使用 `px × 2` 公式(不乘 1.7442),偏差 > 2rpx 即 P4
|
||
- **结构缺失/顺序错误**:直接 P0,不进入测量
|
||
|
||
#### 2.2 审计报告模板
|
||
|
||
```markdown
|
||
# <page> 结构化审计报告
|
||
|
||
## 基本信息
|
||
- 页面:<page>
|
||
- 审计日期:YYYY-MM-DD
|
||
- H5 元素总数:N
|
||
- MP 元素总数:M
|
||
- 结构完整性:✅ 通过 / ❌ 缺失 K 个元素
|
||
|
||
## 结构完整性校验
|
||
| # | H5 元素 | MP 状态 | 问题 |
|
||
|---|---------|---------|------|
|
||
| 7 | .env-arrow svg | ❌ 缺失 | MP 不支持 inline SVG,需导出 |
|
||
|
||
## 偏差汇总
|
||
| 级别 | 数量 | 占比 |
|
||
|------|------|------|
|
||
| ✅ 通过 | XX | XX% |
|
||
| ⚠️ P4-P7 | XX | XX% |
|
||
| ❌ P0-P3 | XX | XX% |
|
||
|
||
## 逐元素偏差明细
|
||
(按映射表 # 排序,仅列出有偏差的属性)
|
||
|
||
| # | 元素 | 属性 | H5 值 | 理论 rpx | MP 值 | 偏差 | 级别 | 修正建议 |
|
||
|---|------|------|-------|---------|-------|------|------|---------|
|
||
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
|
||
|
||
## 不可消除差异(不计入偏差)
|
||
- 字体渲染差异(Noto Sans SC vs 系统字体)
|
||
- 行内元素高度系统性偏小 ~7%
|
||
- 抗锯齿差异
|
||
```
|
||
|
||
#### 2.3 迁移前审计 vs 迁移后对比
|
||
|
||
| 维度 | 迁移前审计 | 迁移后对比 |
|
||
|------|-----------|-----------|
|
||
| 输入 | H5 源码 | H5 源码 + MP 源码 |
|
||
| 映射表 MP 列 | 留空 | 填入实际选择器 |
|
||
| 测量端 | 仅 H5 | H5 + MP 双端 |
|
||
| 产出 | 映射表 + 理论 rpx 值 | 偏差审计报告 |
|
||
| 用途 | 指导 WXSS 编写 | 验证迁移质量 |
|
||
|
||
迁移前审计产出的映射表直接作为迁移后对比的输入——MP 开发完成后,填入 MP 选择器列,跑结构完整性校验 + 逐级测量,即可得到偏差报告。
|
||
|
||
---
|
||
|
||
## Tailwind → WXSS 完整速查表
|
||
|
||
### 字号与行高
|
||
|
||
| Tailwind | H5 px | rpx | 说明 |
|
||
|----------|-------|-----|------|
|
||
| text-xs | 12px / 16px | 22rpx / 28rpx | 字号 / 行高 |
|
||
| text-sm | 14px / 20px | 26rpx / 36rpx | 字号 / 行高 |
|
||
| text-base | 16px / 24px | 28rpx / 42rpx | 字号 / 行高 |
|
||
| text-lg | 18px / 28px | 32rpx / 50rpx | 字号 / 行高 |
|
||
| text-xl | 20px / 28px | 36rpx / 50rpx | 字号 / 行高 |
|
||
| text-2xl | 24px / 32px | 42rpx / 56rpx | 字号 / 行高 |
|
||
|
||
⚠️ Tailwind `text-*` 同时设置 font-size 和 line-height。MP 迁移时必须同时迁移两个属性,遗漏 line-height 会导致行高塌陷。
|
||
|
||
### 间距
|
||
|
||
| Tailwind | H5 px | rpx |
|
||
|----------|-------|-----|
|
||
| p-1 / gap-1 | 4px | 8rpx |
|
||
| p-1.5 / gap-1.5 | 6px | 12rpx |
|
||
| p-2 / gap-2 | 8px | 14rpx |
|
||
| p-3 / gap-3 / space-y-3 | 12px | 22rpx |
|
||
| p-4 / gap-4 | 16px | 28rpx |
|
||
| p-5 / gap-5 | 20px | 36rpx |
|
||
| p-6 / gap-6 | 24px | 42rpx |
|
||
| p-8 / gap-8 | 32px | 56rpx |
|
||
|
||
⚠️ `space-y-N` 换算陷阱:严格按精确公式 `ceil(px × 1.7442 / 2) × 2`,不要心算跳步。
|
||
例:`space-y-3` = 12px → 12×1.7442=20.93 → ceil(20.93/2)×2 = ceil(10.47)×2 = 22rpx(不是 20rpx)。
|
||
|
||
### 常用 px → rpx 对照
|
||
|
||
```
|
||
2px → 4rpx 3px → 6rpx 4px → 8rpx
|
||
5px → 10rpx 6px → 12rpx 8px → 14rpx
|
||
10px → 18rpx 11px → 20rpx 12px → 22rpx
|
||
14px → 26rpx 16px → 28rpx 18px → 32rpx
|
||
20px → 36rpx 24px → 42rpx 28px → 50rpx
|
||
32px → 56rpx 36px → 64rpx 40px → 70rpx
|
||
44px → 78rpx 48px → 84rpx
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
## 附录 A:measure_gaps.py 详细用法
|
||
|
||
路径:`scripts/ops/measure_gaps.py`
|
||
|
||
### 基本用法
|
||
|
||
```bash
|
||
# 测量页面内所有 .task-card 元素的尺寸和间距
|
||
uv run python scripts/ops/measure_gaps.py task-list --selectors ".task-card"
|
||
|
||
# 测量多个选择器(按 DOM 顺序,计算相邻间距)
|
||
uv run python scripts/ops/measure_gaps.py board-finance --selectors ".summary-header" ".summary-content" ".grid-cols-3"
|
||
|
||
# 指定两个元素的直接间距
|
||
uv run python scripts/ops/measure_gaps.py task-list --pairs ".sticky-header" ".task-card:first-child"
|
||
|
||
# 页面中下方元素(需 scrollTop)
|
||
uv run python scripts/ops/measure_gaps.py performance --selectors ".perf-section" --scroll 1200
|
||
```
|
||
|
||
### 输出内容
|
||
|
||
- 元素尺寸表:top_px, h_px, paddingT/B, marginT/B, gap, fontSize, lineHeight, h_rpx
|
||
- 相邻元素垂直间距表:gap_px 和 gap_rpx
|
||
- audit.md 可直接粘贴的 Markdown 表格
|
||
|
||
### 常用 CSS 选择器快查
|
||
|
||
| 元素类型 | 选择器示例 |
|
||
|---|---|
|
||
| 页面内边距容器 | `.px-4`, `.px-6`, `[class*="px-"]` |
|
||
| 卡片 | `.task-card`, `[class*="card"]` |
|
||
| 列表项间距 | `.list-item`, `li`, `[class*="item"]` |
|
||
| Sticky 头部 | `.sticky`, `.filter-bar`, `[class*="sticky"]` |
|
||
| Banner | `.banner-bg`, `[class*="banner"]` |
|
||
| 标签/徽章 | `.tag`, `.badge`, `[class*="tag"]` |
|
||
|
||
---
|
||
|
||
## 附录 B:图像反推验证(截图偏差定位)
|
||
|
||
当 diff 图显示某元素位置偏移时,用截图像素反推实际间距:
|
||
|
||
```
|
||
实际间距(px) = diff 图中偏移像素数 ÷ DPR
|
||
DPR = 1.5
|
||
示例:diff 图中元素 A 比 H5 下移 9 像素
|
||
实际偏差 = 9 / 1.5 = 6px → 查速查表 → 12rpx
|
||
应调整 WXSS 中对应 margin/padding
|
||
```
|