12 KiB
间距测量与 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 拆解流程
- 读取 H5 源码(
docs/h5_ui/pages/<page>.html),识别页面首层容器 - 对每个首层容器,递归拆解子元素,直到到达叶子节点
- 叶子节点定义:单一样式属性可描述的最小视觉单元
- 文字 span(font-size + color + weight 即可描述)
- 图标 image / SVG
- 纯色/渐变 view(background 即可描述)
- 分隔线(border 即可描述)
- 为每个节点记录:层级深度、CSS 选择器、Tailwind 类名、角色描述
0.2 H5 审计映射表(迁移前必做)
拆解完成后,产出结构化映射表。此表是后续所有工作的基准:
## <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
// 测量单个元素的完整属性
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(批量测量)
uv run python scripts/ops/measure_gaps.py <page> --selectors "<sel1>" "<sel2>" ...
1.4 MP 端测量(SelectorQuery)
// 微信开发者工具 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 测量结果记录格式
每个元素的测量结果追加到映射表:
| # | 元素 | 属性 | 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 审计报告模板
# <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
基本用法
# 测量页面内所有 .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