首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >IR 技术:在网页视觉转换中的应用

IR 技术:在网页视觉转换中的应用

原创
作者头像
OneCode
发布2026-09-16 20:24:48
发布2026-09-16 20:24:48
580
举报
文章被收录于专栏:ooderAgentooderAgent

1. 背景:大模型设计的 UI/UE 如何落地私有框架

核心问题:大模型已经能高质量地"设计"UI/UE——直接产出可运行的 HTML 原型 (我们的全部原型即由 LLM 生成)。但企业内部的落地目标往往是私有技术框架 (自研组件引擎、私有组件库),二者之间隔着组件模型、样式体系与布局引擎的巨大差异。 "设计产出"到"框架程序"之间的转换效率,决定了设计迭代能否当天生效。

1.1 常用技术路径对比

路径

做法

问题

代码直译 / 转义翻译

LLM 把 HTML 逐段"翻译"成私有框架代码

每次生成不可复现、token 成本高、样式靠猜、无法回归审计;框架 API 一变全部重来

样式解析 + 规则引擎

解析 CSS/内联样式,按规则映射到框架组件与属性

确定性最好,但规则要落在一份稳定的结构化数据上——直接对 DOM 写规则会与 DOM 细节耦合

多模态反推

模型看设计稿截图直接生成框架代码

视觉损失大(字号/颜色/间距全是估的),不可审计,无法批量

设计规范适配层

约束设计稿使用标准组件,再一一映射

牺牲设计自由度;LLM 生成的原型恰恰是无约束的 HTML/CSS

1.2 最终选择:IR(中间表示)

这是编译器的经典思路:前端语言无关,后端目标无关。 任何来源(HTML/CSS 原型、未来的设计稿格式)都编译成同一份 IR; IR 再由各自的代码生成器输出到任意私有框架。选它的三个决定性理由:

  1. 确定性:转换是纯函数式的编译过程,同一输入永远同一输出——LLM 只负责"设计",落地交给工具链;
  2. 可审计:IR 与产物同构,质量指标(文本承载率、样式保真率)可自动对账、可接 CI;
  3. 可演进:引擎 API 变化只影响"IR → 框架"一层的映射表,前端提取层完全不动。

1.3 OODUI 框架简介

OODUI 是自研的移动端优先 UI 引擎,本管的转换目标即它:

  • 组件 = 虚拟节点树:每个组件(ood.UI.Block / Label / Button / Gallery / List / ToolBar…) 由模板定义若干虚拟节点(KEY 根节点、CAPTION 文本、ICON、BORDER、PANEL 内层容器…), 样式与内容必须"投递"到正确的虚拟节点才会生效;
  • 样式 = CS:组件级自定义样式,按虚拟节点键下发(对 KEY/BORDER 可靠,个别键有坑,见 §3);
  • 布局:列布局 conLayoutColumns + dock 停靠 + 绝对定位三件套, 与浏览器 flex 不等价
  • 载体:组件树以 .cls(JSON)描述,服务端反序列化后由 showModule 渲染进 DOM。

1.4 为什么还需要"一层"IR,而不是直转

直转器(HTML 直接映射组件)很快撞上三堵墙:

  • 样式真相分散——外部 CSS、<style> 块、内联 style 三处叠加,还要经过级联与特异性排序;
  • 无法审计——没有与产物同构的中间表示,"字号保真率多少"这类问题无法回答;
  • 判定无落脚点——"6 个同构卡片应聚合成 Gallery"这类判断需要同时看结构、样式与内容。

IR(中间表示)把这三件事一次性编译完成:先物化出每个节点的计算样式与规范化结构, 后续所有语义判定、组件映射、审计对账都只依赖 IR、只读不猜。

2. 管线总览

图 1 | 五级管线与三条保障带、审计闭环

提取层 html2ir.mjs 把 CSS 级联 + 内联 style 展开为每节点的计算样式; 语义层 semantic2ouc.mjs 完成角色推断、组件映射与样式注入,产出 .ouc.json, 服务端反序列化为 .cls 组件树交引擎渲染。

2.1 IR 节点结构(技术细节)

图 2 | IRNode 字段与三大消费方

代码语言:javascript
复制
{
  "tag": "section", "classes": ["gt-stat-grid"],
  "children": [ /* 规范化 DOM 树 */ ],
  "icon": "ri-user-line", "src": null,
  "text": ["872", "刷题总数"],
  "style": {
    "layout":     { "display": "grid", "position": "absolute", "top": "0" },
    "paint":      { "background": "linear-gradient(...)", "color": "#fff" },
    "typography": { "font-size": "1.667em", "font-weight": "700" },
    "box":        { "width": "394px", "border-radius": "1em" }
  }
}

级联展开算法:收集所有命中节点的规则(外部 CSS 按 specificity × 出现序、 <style> 次之、内联 style 最高),排序后逐属性覆盖写入 flat, 再按属性分类归入四组。这一步等价于浏览器 getComputedStyle 的离线实现, 是整条管线的地基——初版漏掉内联 style 时,字号/颜色覆盖率长期失真、进度条完全无法识别。

3. 角色推断:判定链(顺序即语义)

图 3 | inferRole 从上到下短路命中;三个历史事故全部源于顺序错误

⚠ 同构签名 = tag + classes(阈值 ≥3),类名仅用于结构分组、严禁参与语义推断; 复杂子项(item 内层仍是列表)递归拆分为嵌套节点,避免整段内容被压扁丢弃。

3.1 组件转换类型对照表

语义角色

OUC 组件

内容/样式槽位

已定论的关键约束

PageHeader / TabBar

ood.UI.ToolBar

items[]

引擎无 bottom 停靠,TabBar 实际渲染在顶部(已知差距)

HeroBanner

ood.UI.Block

KEY=渐变+display:block;子节点 Label/Button 绝对定位

CS.PANEL 对 Block 不生效 →properties.background='transparent'触发 action 打透;无 IR 高度时须兜底

StatGroup

ood.UI.Gallery

items[].value / caption;width:100%

VALUE 节点会渲染(旧"不渲染 value"已勘误,勿再双写 comment)

GridGroup

ood.UI.Gallery

caption / imageClass / comment

图标必须走 imageClass(iconFontCode 会被当文本画出类名)

NavList / CardList

ood.UI.List

caption / ext / imageClass

List 渲染 {ext} 不渲染 {sub};TreeListItem 无 iconFontCode

ProgressItem

ood.UI.ProgressBar

value / caption

识别依赖内联样式并入(原型宽度写在 style 上)

Title / Caption

ood.UI.Label

caption + CS.CAPTION

properties.fontColor 必须是 CSS 变量名,排版走 CS.CAPTION 直注

Icon

ood.UI.ContentBlock

imageClass

判定必须先于 EmptyState(texts≤2 包含 0)

EmptyState

ood.UI.ContentBlock

caption / subtext / imageClass

必须写 imageClass,否则产出空壳(曾 29 个,已清零)

Action

ood.UI.Button

caption + CS.KEY

默认灰底 rgb(245,245,245)+display:block → 须覆盖为 inline-block/透明

Panel(兜底容器)

ood.UI.Block

conLayoutColumns:1 + KEY

壳层默认 inline-block 会收缩 → 强制 display:block

对照表各槽位在真实页面上的落地效果——首页集中了 Banner、Gallery 宫格、统计组、List、ToolBar 五类组件:

首页 | 左:HTML 原型,右:产物在 OODUI 引擎渲染(HeroBanner + GridGroup + StatGroup + List + TabBar)

个人中心 | 两组 StatGroup(含彩色数值)与 NavList,"value 会渲染"结论的来源页面

4. 布局归一与审计闭环

容器布局只有两种合法形态:A 自由布局(conLayoutColumns:1,子节点交引擎列布局)、 B 绝对定位(展示型容器,工具从 IR 算出子节点 left/top/height 显式下发)。 配套约束:容器去 padding(折进子坐标防双计)、去 flex/gap 无效属性但 display 必须定为 block。

审计闭环:IR 与产物同构,审计工具逐页量化文本/图标承载与样式保真。 修复一轮后(17 页):文本 81.1%→86.2%、图标 49.5%→80.4%、空壳组件 29→0。 宿主页 ?probe=1 输出组件 computed box+背景、?shot=1 支持无头截图—— 所有观察都可复现。

布局归一的效果在"视频课程"页最为直观:顶部深红渐变 Banner(HeroBanner)满宽上色、 分区卡片(Panel + Gallery)撑满列宽——这两处正是"白 PANEL 盖渐变"与"壳层收缩"两个通病的主战场:

视频课程 | 布局归一后的 Banner 渐变与满宽卡片

5. 转换质量实拍:多组件嵌套页面

智能家居首页覆盖了问候区、快捷场景宫格、房间 2×2 宫格与设备列表的嵌套组合, 是多组件协同转换的代表性页面(首页/个人中心/视频课程的截图已按主题分布在前文 §3、§4):

智能家居 | 场景宫格、房间 2×2 宫格、设备列表(左原型 / 右引擎渲染)

剩余差距:Banner 内头像/图标定位有偏差;无头环境图标字体偶发缺字。均在审计"未解决"清单中。

6. 方法论小结

  1. 中间表示是审计的前提:没有同构 IR,"转换质量"只能是主观印象;
  2. 判定顺序是语义的一部分,要像接口契约一样对待并注释清楚;
  3. 对引擎每个字段约定都要追溯到模板源码,猜槽位 = 静默丢数据;
  4. 样式真相一次性物化(级联+内联+特异性),之后只读不猜;
  5. 不可重现的观察不算证据:缓存、时序、截图都要做成确定性开关。

7. 下一步

  • 用几何审计(computed box 对比)把 Banner 子元素定位误差量化进指标;
  • 组件能力缺口(卡片多槽位、列表双图标、圆形、进度条)已提交引擎侧评估;
  • 审计报告接入 CI,指标回退即阻断合入。

—— 完 ——

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 1. 背景:大模型设计的 UI/UE 如何落地私有框架
  • 1.1 常用技术路径对比
  • 1.2 最终选择:IR(中间表示)
  • 1.3 OODUI 框架简介
  • 1.4 为什么还需要"一层"IR,而不是直转
  • 2. 管线总览
  • 2.1 IR 节点结构(技术细节)
  • 3. 角色推断:判定链(顺序即语义)
  • 3.1 组件转换类型对照表
  • 4. 布局归一与审计闭环
  • 5. 转换质量实拍:多组件嵌套页面
  • 6. 方法论小结
  • 7. 下一步
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档