Files
Neo-ZQYY/_DEL/pixel-audit/steering/measure.md
2026-03-15 10:15:02 +08:00

346 lines
12 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.
# 间距测量与 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. 叶子节点定义:**单一样式属性可描述**的最小视觉单元
- 文字 spanfont-size + color + weight 即可描述)
- 图标 image / SVG
- 纯色/渐变 viewbackground 即可描述)
- 分隔线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
方式 APlaywright 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
```
---
## 附录 Ameasure_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
```