This commit is contained in:
Neo
2026-03-15 10:15:02 +08:00
parent 2dd217522c
commit 72bb11b34f
916 changed files with 65306 additions and 16102803 deletions

43
_DEL/pixel-audit/POWER.md Normal file
View File

@@ -0,0 +1,43 @@
---
name: "pixel-audit"
displayName: "H5→MP 像素测量与 rpx 换算"
description: "H5 页面结构化拆解、逐级元素测量、px→rpx 换算、偏差审计方法论。用于迁移前 H5 审计和迁移后双端对比。"
keywords: ["rpx", "间距测量", "measure", "像素", "pixel", "px", "换算", "Tailwind", "wxss", "间距", "gap", "spacing", "审计", "拆解", "映射表", "偏差"]
author: "NeoZQYY"
---
# H5→MP 像素测量与 rpx 换算
精确测量 H5 页面元素尺寸与间距,换算为小程序 rpx 值。
提供结构化拆解→逐级测量→偏差审计的完整方法论,指导 H5→MP 迁移和双端对比。
核心工具:
- `scripts/ops/measure_gaps.py`Playwright headless 测量)
- Playwright MCP `browser_evaluate`(等效 JS 测量)
## rpx 速查
```
精确公式rpx = ceil(px × 1.7442 / 2) × 2
简化心算rpx ≈ px × 2 × 0.875 取偶6px/14px 处有 2rpx 偏差)
圆角border-radius = px × 2
2→4 4→8 6→12 8→14 10→18 12→22
14→26 16→28 20→36 24→42 28→50 32→56
```
## 偏差判定标准
| rpx 偏差 | 级别 | 处理 |
|----------|------|------|
| ≤ 2rpx | 通过 | 无需修正 |
| > 2rpx 且 ≤ 4rpx | 警告P4-P7 | 像素级精调 |
| > 4rpx | 不通过P0-P3 | 必须修正 |
## Steering
| 文件 | 内容 |
|------|------|
| `measure.md` | 结构化拆解方法论、H5 审计映射表、逐级测量流程、偏差审计规则、rpx 换算公式与速查表、measure_gaps.py 用法、MP 反向验证 |
加载:激活 Power → `readSteering("measure.md")`

View File

@@ -0,0 +1,345 @@
# 间距测量与 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
```