在持续迭代的真实项目中,前端工程通常已经沉淀了既有的组件、页面结构与业务逻辑。面对不断更新的 Figma 设计稿,如何将其稳定还原到既有工程中,同时避免破坏原有的代码结构与业务运行,是我们在实践中面对的核心问题。

这次实践的核心,是借助 Agent 把从设计稿到前端代码的还原做成一条可反复运行、可验证的工程流程。在真实的工程约束下,设计稿往往不完全规范,既有工程的代码不能被随意重写,反复迭代的成本与视觉结果又需要清晰可验。在这些约束下做出的取舍与机制设计,构成了这套流程能够持续运转的基础。

后文将从实际迭代中遇到的问题出发,沿着输入约束、版本复用、视觉验证到旧页边界的主线,依次介绍我们在各个环节建立的规则与机制,以及这些机制如何串联成一套完整的还原流程。

全套方案流程总览

五类高频出现的还原问题

在实际迭代中,我们遇到了旧页面新增筛选模块容易被整页重写的问题。需求原本只是在既有页面中加入筛选模块,但在自动化还原时,生成流程往往把包含既有页面在内的区域整体用基础代码重写了一遍。

现有设计还原问题

这一现象促使我们重新审视自动化还原中的流程机制。在推进从 Figma 到真实前端代码的过程中,主要存在五类问题:

  • 首先是设计语义的丢失。在设计交付中,设计稿中的组件可能被解除实例化(detach)。一旦组件关联被解除、可识别的组件语义随之变弱,代码生成流程无法直接获取其原有的通用组件信息,容易退化为提取坐标、颜色与尺寸,直接生成基础结构与样式。

  • 其次是多页面样式的统一难题。单页面的局部还原通常更容易处理,但在面对多个连续页面时,若缺乏连贯的样式与结构约束,不同页面生成的代码便难以维持同一套设计语言,容易出现间距、字号与色彩配置不一致的情况。

  • 第三是标注信息与真实界面的混淆。为了说明交互逻辑,设计稿中常常包含批注文字或说明区域。若缺乏明确的区分机制,代码生成流程难以分辨哪些是说明性内容、哪些是需要渲染的真实界面,容易将说明文案一并编写进页面代码中。

  • 第四是素材导出策略的模糊。页面中的图形素材是否需要导出、以何种格式导出、导出倍率以及是否属于占位资源,若在设计侧没有结构化的表达规则,代码生成流程便缺乏依据,容易造成素材处理混乱或占位资源被错误打包。

  • 最后是旧页面局部改造中的全量覆写。在既有页面发生局部增删时,若无法清晰界定改动边界,生成流程容易将局部调整误判为整体重构,进而重写既有工程中已有的逻辑与结构。

这五类问题表明,设计语义、信息组织、改动范围与验证方式,需要在设计稿输入与前端工程实现之间建立统一的机制约束。其中,反复获取和转译设计信息还增加了迭代成本,成为后续调整 Loop 的直接原因。

实现约束层

在生成代码之前,必须先建立一层面向前端工程的实现约束。真实业务场景中的设计稿往往不完全规范,存在图层未命名或组件被解除实例化(detach)的情况;而既有工程拥有自身成熟的组件库与设计系统,若缺乏约束,Agent 仅凭外观视觉容易猜测实现方式,退化为生成原生标签或随意编写样式。为此,需要在设计输入与代码生成之间引入实现约束,分别从全局原则、能力检索与边界纠偏三个维度为 Agent 划定生成边界:

从项目全局到特殊案例,逐层约束

项目级规范

项目级规范用于明确代码工程的技术选型与组织原则。我们在工程根目录下的 AGENTS.md 中以机器可读的方式写明前端组件的复用要求,明确规定凡是能对应到现有组件库的能力,就优先复用既有组件,基于工程既有设计系统进行搭建。

知识索引

有了规范要求,还必须让执行方能够检索到具体能力。我们建立了结构化的知识索引,并将组件库的 API 能力封装为工具能力(Skill)提供给 Agent。执行方在面对界面结构时,可以主动查询组件库的类型定义、支持的属性组合以及标准的插槽用法,而不是仅凭外观去猜测实现方式。

错误情况补充

真实工程中总会遇到非标准的特异场景。通过持续沉淀错误情况补充,我们将历史迭代中出现的误判案例、易混淆样式以及特殊适配逻辑转化为负向规则和边缘案例索引,防止相同的解析错误在后续任务中重复发生。

这三者相互配合:项目级规范给出组件复用的全局原则,知识索引提供可查询的工程真实能力,错误情况补充则修正已出现过的偏差,共同把设计稿中表达的视觉意图约束在既有工程的技术轨道之内。

组件映射:语义判断与真实 API 确认

在确立了实现约束层后,核心动作是解决设计稿节点到代码组件的映射。我们在机制上得出的经验是:把「语义判断」与「真实 API 确认」划分为先后承接的两层。

在第一层,component mapper 关注抽象语义判断,分析区域与元素的功能角色;随后第二层的 provider 介入,将这一抽象角色对应到前端工程所使用的真实组件库上,确认具体的组件名称、属性参数、样式 token 与版本。

之所以做这种双层切分,是因为设计稿在进入实现时,往往处于未命名、命名混乱、节点 detach、以及缺乏 auto layout 这四种非理想状态之一。在这类不规范的输入下,如果指望解析器一步到位直接翻译出最终的代码组件,容易产生幻觉或直接放弃组件复用。

在映射过程中,需要先检查的能力集合包括:属性(props)、变体(variants)、插槽(slots)、设计令牌(tokens)、组件复合模式(composition)以及状态响应能力。凡是能对应到现有组件库的能力,就优先复用既有组件。

我们可以通过三个说明性例子来看这种推断过程:

描边按钮的判定

在设计稿中,面对一个被 detach 的按钮,图层可能只是简单的矩形和居中文本。第一层 mapper 先将其识别为一个需要交互的按钮类控件,而不直接将其写死为某种特定的代码样式。随后,第二层 provider 介入,查询组件库中的 Button 组件,并确认当前组件库中表达描边样式所使用的具体属性配置,进而生成复用组件的代码,而不是输出带有原生边框样式的原生按钮标签。

弹窗内部区域的划分

在一个业务弹窗中,设计稿可能由多个矩形容器组合而成。第一层 mapper 先判定其整体为模态浮层,并将其内部划分为 Header 标题区、Content 滚动内容区和 Footer 动作区。第二层 provider 随后将这些区域分别对应至真实组件库的弹窗子组件与插槽中,复用组件库为这类结构提供的既有能力。

图标角色的确认

对于在输入框或按钮区域出现的图形元素,第一层 mapper 根据其位置与容器关系,判断其属于伴随性操作图标还是装饰图形。进入第二层后,provider 按命名线索与工程既有图标能力去匹配对应图标组件,从而引入组件库中的图标,而不是内联一段不易维护的原生矢量代码。

小饭团把已有组件放入界面板的匹配槽位,表达组件复用

通过这种双层解耦的方式,代码生成过程减少了对绝对坐标和原生 HTML/CSS 的依赖。在同样使用 Codex 搭配 GPT 5.4 的测试中,组件正确调用率从约 50% 提升到接近 100%。

标注协议:说明与真实设计稿分开

解决了组件本身的识别,下一个环节是处理画布上的辅助信息。在真实设计流程中,画板上往往分布着业务说明与状态流转指示,如果这些内容与真实界面杂糅在一起,自动化工具就会产生识别漂移。

为了理清信息,我们推行了标准标注协议。我们使用两个轻量级的 Figma 插件分别承担设计标注与素材命名的辅助标记工作,通过约定配合 Agent 侧的提示约束,实现说明与界面的分离。

在结构组织上,所有需要被工程识别的内容都遵循明确的前缀规范:业务说明与交互指引统一使用 {指引 Frame 名称}/Figma Annotation/ 作为前缀;而真实待实现的界面稿则使用 {指引 Frame 名称}/ 作为前缀。界面的入口关系同样由命名前缀表达。通过容器命名上的显式隔离,解析流程可以区分出哪些信息仅用于理解业务流程,哪些结构是需要真实呈现在代码里的视图基准。

在落实这一协议时,存在一个容易出错的地方:标注容器中可以嵌套真实设计稿。在实际绘制过程中,设计稿有时为了排版紧凑,会在一个标注说明卡片内部内嵌某个需要真实实现的子界面片段或局部表单。如果解析逻辑简单地将带有标注前缀的容器整体忽略,就会导致嵌套在其中的真实界面稿被一并当成说明文本丢弃。

因此,前缀解析时要能识别标注前缀里的说明文字,同时不把其中嵌套的真实设计稿一并丢掉。依靠命名前缀进行区分,既将说明文案提取为理解交互的上下文线索,又保留了嵌套其中的真实界面结构。

素材策略:三类标签决定导出行为

在划分了界面与标注之后,针对界面内部包含的图形资产,需要建立确定的导出规则。如果交由模型自行判断某个图形是以矢量导出、导出为位图还是属于占位,结果往往不稳定。

我们通过辅助插件,在设计稿的图层命名中引入了三类标签,直接决定下游代码生成时的资源处理行为:

  • <icon>:标识矢量图标,解析流程将其直接导出为 SVG;

  • <img>:针对插画等实际视觉资产,导出 3x PNG,后续增加了压缩为 WebP 的导出优化;

  • <export_null>:标识占位图,表示这张占位图不需要导出。

不同视觉资产导出策略

这些标签把是否导出、使用什么格式和导出倍率的判断提前放到了设计侧,Agent 可以据此处理素材。

在这一套围绕标注前缀与素材标签的命名协议落地后,我们的工程记录显示,标注与素材规则的测试符合率为 100%;5.6 sol 之后后续几个月没有收到不良反馈。

Loop 的代价:早期为什么烧光额度

当我们理顺了语义映射与标注协议后,便尝试搭建一套自动化的迭代循环(Loop):让 Agent 读取设计稿、生成代码、运行项目、比对界面,如果有出入就继续修改,形成自我修正的闭环。

然而,在早期的实验中,仅仅进行了几次页面的迭代还原,当时的月度额度就被消耗殆尽。

复盘当时消耗的原因,问题出在闭环每一轮都要重新请求设计信息并重新转译,重复的请求与转译叠加使支出迅速累积。

在自动化闭环中,微调代码往往是针对细小的局部。举一个小改动的例子,比如调整 2px 外边距或修改文本颜色值,这类代码变动通常只涉及几行甚至几个字符的调整。但由于最初的闭环逻辑将获取设计基准与代码生成紧密捆绑,为了验证微调是否生效,系统在每一轮微调中都会重新向设计源发起数据请求,并将获取到的节点数据重新转译为代码上下文。

在这种机制下,上游设计源在微调期间并未发生任何变动,提供的数据与上一轮完全一致,但下游每一次局部的尝试,都在被迫重复消化相同的设计输入。局部调整的频次越高,这种重复请求与重复转译的开销累加就越快,最终在短短几次还原后便耗尽了当时的月度额度。如果不打破这种每一轮都重新组织设计上下文的做法,微调闭环在成本上就无法维系。

每批每版本集中采集与时间戳版本快照

面对这种资源损耗,我们对数据采集与上下文组织进行了调整,将动态比对与设计采集这两部分从工程链路上解耦。

调整循环获取原始数据的入口

我们调整了在微调循环中实时拉取设计稿的做法,改为批量版本机制:针对同一批设计内容、每个版本集中采集一次,转译结果按时间戳版本快照保存在服务器上;同一版本的后续所有比对与微调直接复用该快照,不再重复向设计源拉取;设计确有更新时另建一个新时间戳版本。

固定版本还为多轮比对提供了稳定的依据。若闭环始终依赖实时拉取设计源,一旦设计画布发生临时变动,代码生成的参考依据就会产生漂移,上一轮与下一轮的比较条件就可能不同。同时,外部请求的高频发生也会阻碍闭环的常态化运行。

这种调整体现了一种明确的工程取舍:我们主动放弃了在单次微调循环中对设计稿即时变动的感知。在特定版本周期内,画布上的临时改动不会同步进入正在执行的代码闭环。这个取舍的边界在于:时间戳版本快照保存和复用的是设计内容及其转译结果,它的职责是提供静态、稳定的比对标尺;而真实的前端代码实现才是动态演进、不断被编译、渲染并拿来比对的动态对象。通过将转译结果固化为快照,代码微调可以始终锚定在确定的基准之上进行推演,而外部的重复开销也被有效阻断。

在实际工程实践中,这套办法显著节约了 token 和时间;Codex 使用 5.5 模型时,还原度超过 90%。

小饭团用放大镜比较固定版本的设计卡与实现卡,表达基准复用与循环比对

让比对成立:状态、视口、数据与 DOM Bounds

有了稳定的快照作为设计基准,接下来需要明确比对的具体条件。

若直接在本地运行项目截取图像与设计稿比对,在真实的 Web 页面中容易产生无效误差。比对之所以必须满足一系列严格的前置条件,是因为视觉差异的产生往往由多种环境因素交织而成,若不提前排除无关干扰,比对结果就无法真实反映样式的还原质量:

使用 5 重规定约束对比

统一浏览器视口

比对前,我们先统一浏览器 viewport,让实现页面在约定的可用宽度和高度下渲染。现代前端页面普遍采用流式排版与弹性布局,容器尺寸与换行行为直接受制于浏览器视口的大小。如果实现页面的浏览器视口宽度与设计基准设定的视口不一致,即使 CSS 代码完全符合规范,元素也会因为可用宽度改变而被迫折行或拉伸。若将这种由于视口不统一引起的排版变动误判为样式错误交给 Agent 修复,就会错误地去改动原本正确的内边距或固定宽度,导致布局更加混乱。因此必须确保页面在统一的浏览器视口配置下渲染。

目标状态流转

真实的业务界面往往处于特定的交互状态下,例如展开的下拉菜单、弹层或表单校验态。设计稿所展现的通常是这些具备具体交互内容的终态,而页面刚加载完毕时处于默认的初始状态。如果直接拿初始页面与终态设计稿做比对,差异图上整块激活区域都会被判定为错误,这并非样式实现缺陷,而是因为页面尚未步进到目标交互节点。自动化脚本必须先驱动页面模拟交互,进入对应的目标状态后再执行比对,使双方处于同一逻辑截面上。

固定数据与滚动位置

界面的列表条数、文本内容和滚动条位置需要固定。如果本地运行环境返回的数据条数与设计稿不一致,或者文本字符长度存在差异,整个容器的高度和内部流式排版就会发生改变。数据条数变化会让 diff 变化,不能把这类差异全归咎于 CSS 样式错误。如果未能固定 Mock 数据,系统就会试图通过压缩组件间距或调整外边距去勉强对齐高度,导致代码偏离既有规范。同理,滚动位置的偏移也会造成全局像素错位,必须在相同滚动锚点下进行截图比对,使比对完全聚焦于视觉实现本身。

主题与加载完成条件

页面在比对前需要确保主题设置一致,并满足加载完成条件:样式表注入就绪、图表与字体渲染完成、骨架屏退场。页面初次加载时常伴随字体替换与资源异步加载的过渡阶段,如果过早截取半成品画面,比对引擎就会把临时的占位状态当成界面缺陷进行误报。因此必须在页面完全达到静态稳定状态后触发比对。

DOM Bounds 的定位作用

单纯的图像差异对比只能指出画面上像素不一致的区域,无法直接解释底层的结构原因。例如某个组件在画面上出现了位移,像素差分只能显示大面积的颜色不符,却无法说明究竟是该组件自身的边距设置有误,还是相邻同级元素尺寸改变引发了推挤,亦或是父级容器的内边距缺失。DOM bounds 检测在比对闭环中的作用,是提取真实渲染树中关键节点的盒模型几何边界,为闭环提供位置与尺寸的证据,辅助定位差异所在的具体 DOM 节点,使后续的代码微调能够基于几何边界证据展开。

视觉闭环:六步执行与差异记录

在统一了基准快照与比较条件后,我们将前端还原的验证过程梳理为六步闭环流程:

第一步是环境核查,核验浏览器视口、Mock 数据与基准配置,确保运行环境处于预设状态;第二步是真实页面截图,驱动页面步进至目标状态,捕获实际渲染图像;第三步是 DOM bounds 检测,提取渲染树中关键节点的几何盒模型边界,获取位置与尺寸证据;第四步是视觉比对,将真实页面截图与设计快照进行比对,输出差异图与结构化差异数据;第五步是差异修复,由 Agent 结合差异数据与 DOM 边界信息,针对性微调代码与样式;第六步是结果汇报,输出该轮调整的差异记录与收敛指标。

这六个步骤各有作用:环境核查保证比较条件一致,真实页面截图呈现浏览器中的实际结果,DOM bounds 补充位置与尺寸证据,差异图和 JSON 报告记录偏差。修复后再按相同条件比对,才能判断这一轮修改是否有效。构建通过说明工程可以构建,视觉是否对齐还需要在真实页面中检查。

针对界面差异的量化评估,工程记录采用差异率衡量比对结果,并以 0.15 作为该流程的视觉收敛阈值。

对比效果预览

以下是工程记录中两个案例的数据:

页面 / 模块类型

参考尺寸(宽×高)

真实实现尺寸(宽×高)

最终记录差异率

材料弹窗

608 × 532

608 × 532

0.09788

详情页

1442 × 1878

1442 × 1878

0.08329

两项测试均以参考与实现尺寸对齐为前提,这两个案例达到该阈值,差异率均低于该流程设定的收敛阈值。这表明在比较条件严格受控的前提下,闭环流程能够支持局部的微调与收敛。

旧页面局部改造:边界怎么划

在明确了比对机制后,面对旧页面的局部改造需求,划定改动边界是保证工程稳定的关键。这也是解决旧页面新增模块容易导致全页被重写这一问题的核心所在。

旧页面局部改造容易出现范围失控,原因在于设计表达与工程实现之间存在认知差异。既有页面通常已经在线上承载了真实的业务运行,沉淀了复杂的状态管理、接口契约和业务逻辑。而设计稿主要承载布局、视觉与可见状态,接口、权限与业务规则另有依据,不从设计稿反推。如果缺乏明确的边界约束,生成流程面对一张包含完整页面的设计稿时,容易误以为眼前所见的一切都需要从头实现,进而覆盖原有的成熟逻辑。

在动手编写代码前,先研读设计稿与既有工程,确认目标页面并梳理可复用的模块。涉及多页面的需求,则按一个页面或独立功能逐轮推进:每一轮明确当前范围,使用对应版本的设计基准,在相同页面状态下比对,再根据差异修复。快照减少重复采集和转译的成本,分范围执行让每轮任务更集中,视觉闭环负责检查样式是否逐步对齐。

旧页面的局部调整还需要明确四项约定:

现有页面

显式锁定本次改动所归属的既有文件与挂载位置。这项约定防范的是上下文漂移与脱离主干的失控。当需求仅是在既有页面中增加模块时,如果未明确指定具体的代码文件路径,生成流程在面对整页设计上下文时,容易自行在不相干的目录中新建一套平行的页面代码。虽然新页面视觉上看起来完整,但完全脱离了工程既有的路由体系与全局状态。通过明确锁定现有页面的文件路径,强制改动必须锚定在既有工程的代码节点上。

目标区域

明确划定改动的作用域容器。这项约定防范的是代码修改横向越界引发的级联问题。在局部改造中,改动模块通常与既有的导航、表头或侧边栏紧密相邻。如果不对改动权限做容器级别的限制,生成流程在微调新模块的排版或间距时,极易顺带改动外部父容器或相邻组件的弹性布局属性,导致原本未作改动的临近区域发生排版错乱。把目标区域写清楚,可以约束 Agent 的修改范围,也便于检查它是否改动了相邻区域。

不改动项

明确列出禁止修改的资产清单。在我们整理的案例中,排除项主要包括:表格、分页、详情、接口契约。这项约定防范的是对成熟业务资产与数据通路的破坏性修改。设计稿展示的往往是包含既有表格和详情的完整视图,但其中的数据展示均为静态占位。如果未显式排除这些项,生成流程容易将表格复杂的渲染逻辑、分页联动以及接口契约用简单的静态代码替代,造成既有功能的回归。这些不改动项给代码审查提供了明确依据:检查新增筛选区时,也要确认既有模块没有被顺带重写。

局部比对

将比对范围约束在目标改动区域内。这项约定防范的是全页无关噪点对局部验证的干扰。在复杂的旧页面中,非改动区域往往存在动态变化的数据、时间戳或外部状态。如果对整页进行全局差分比对,这些非改动区域的微小动态差异会在差异图上产生大量噪点,掩盖目标模块内部真实的视觉偏差,使微调方向受到误导。将比对视野收拢在目标局部容器内,排除了外部无关变动的干扰,让验证集中在本次变动的局部区域。局部视觉比对与常规工程验证配合进行:前者检查目标区域的视觉呈现,后者检查页面原有功能与新增交互。

这套针对现有页面、目标区域、不改动项与局部比对的边界控制,适用于新增局部模块、调整局部交互区域以及长页面中的局部区块改造,使局部调整能够保持在受控的范围之内。

小饭团向既有页面的指定区域加入模块,其余模块保留,表达局部改造边界

串联为工程流程

回顾从设计稿到前端代码还原的完整链路,这次实践沉淀出的工程能力主要体现在四个方面:首先是输入规则,通过实现约束层、组件双层映射、标注前缀规范与素材处理标签,将不完全规范的设计表达转化为具有明确工程语义的输入;其次是版本复用,依托每批每版本集中采集与时间戳版本快照,阻断局部微调对外部设计源的重复请求与转译开销;第三是视觉收敛,通过一致的比对条件与六步闭环流程,以差异率阈值判断收敛,为差异修复提供可比的依据;最后是局部改动边界,凭借现有页面、目标区域、不改动项与局部比对四项约定,将修改范围限定在目标区域之内,避免全页覆写。

工程全流程回顾

这些机制之所以能够连成一条流程,关键在于前一环始终在为后一环提供稳定的输入或可比的基准。统一的输入规则明确了组件与素材的工程语义,为生成版本快照提供规范的解析输入;版本快照固化了静态的设计基准,为多轮比对提供了统一的比较前提;而局部改动边界将改动与验证范围约束在特定容器内,让视觉闭环能够集中检查局部的调整效果,使代码微调始终基于既有工程展开。