AI 能读取 Figma,但为什么做出来的页面还是不像?


之前写过一篇 Claude Code 通过 MCP 连接 Figma 的配置笔记。那时候主要解决的是:怎么让 AI 读到设计稿。

这几个月在实际项目里反复做页面对齐,又遇到了另一个问题:设计稿已经读到了,尺寸、颜色、字体也提取了,代码看起来没什么毛病,跑到手机上却还是不像。

有时候很难一下子说清楚哪里不对。大布局是对的,按钮也都在,但文字有点飘,图标有点小,弹窗显得松散,暗色模式又有另一种不协调。

于是继续告诉 AI:“再和设计图对齐一下。”它改几处间距、补几个样式,页面变了,却未必更接近。

后来我开始把“读设计稿”和“验收页面”当成两件事。下面记录几个在 React Native 项目里反复遇到的问题,以及我现在怎么处理。

一、MCP 给的是设计上下文,屏幕上显示的是运行结果

Figma MCP 能提供节点、布局、变量、组件和设计资源。这些信息很有用,但中间还有一段实现过程:

Figma 节点与设计截图
        ↓
项目已有组件、主题和布局规则
        ↓
生成的页面代码
        ↓
浏览器或原生平台渲染
        ↓
真实数据、键盘、弹窗和交互状态

每经过一层,都可能引入偏差。

比如设计里的按钮高 44,代码也写了 44,但组件内部可能还有默认 padding;设计里写的是某个字体,设备上实际显示的却是回退字体;截图里的弹窗没有键盘,真正输入时却要面对键盘和底部安全区。

Figma 官方也专门解释过 MCP 提供什么、AI Agent 负责什么:设计上下文需要由 Agent 结合项目代码来实现,MCP 本身不会替你完成最终页面,也不会自动解决实现偏差。

所以,连接成功只是起点。真正需要核对的是最后那张运行画面。

二、文字不像,先别急着改 margin

这是我最容易花时间的地方。

一个图标和一行文字放在横向布局里,容器设置了居中对齐,看起来文字还是偏上。直觉上会想加一点 marginTop。问题是,这一行调好了,换成数字、换个字号,或者换到另一个平台,偏差又回来了。

原因可能在文字本身,而不在外层间距。

1. 同样的字号,不代表同样的字形

fontSize: 14 只告诉你字号,没有告诉你这行字最终长什么样。

字体文件是否加载、字重是否存在、中文是否被当前字体覆盖、数字是否使用了另一套字体,都会影响结果。中英文混排时,甚至可能在一行里同时发生字体回退。

我现在会先检查实际使用的字体和字重,再看 lineHeight,最后才调整外层间距。否则很容易拿一个补丁去遮住字体问题。

2. 文本框居中,不一定等于字形看起来居中

布局系统对齐的是文本框,眼睛看到的是字形。字体的上升部、下降部和基线,会影响文字在框内的视觉位置。

React Native 还有平台差异。例如 Android 的 includeFontPadding 会影响额外字体留白,官方文档 对此有明确说明。但它是 Android 相关属性,不能当成 iOS 文字偏移的通用修复,也不应该不看字体就全项目关闭。

碰到文字不齐,我会按这个顺序查:

  1. 字体有没有真正生效,当前字符有没有发生回退。
  2. 字重和行高是否与设计要求一致。
  3. 文本容器是否存在额外 padding 或固定高度。
  4. 平台默认行为是否参与了布局。
  5. 最后再考虑少量、局部的视觉校正。

这样排查未必一次就结束,但比不断上下挪一两个像素更容易找到原因。

三、图标尺寸对了,图标本身可能还是小的

另一个很容易误判的问题,是图标的“尺寸”。

下面是一个示意:

图标文件画布:24 × 24
实际图形范围:16 × 16
页面显示容器:24 × 24

代码里给了 24,眼睛看到的主要图形却只有 16。为了让它看起来更大,你可能把容器放大到 30,结果点击区、间距和整行对齐一起受到影响。

我现在会分开看三个东西:文件画布、可见图形、点击区域。

设计里的图标如果有明确资源,就先用那份资源核对。不要仅凭“这是一个设置图标”,换成图标库里长得差不多的版本。不同版本的线宽、转角、内部留白都可能不同,一排放在一起尤其明显。

修正时也要先判断:究竟是资源留白、渲染缩放,还是容器尺寸有问题。把三者混在一起,很容易越改越偏。

四、弹窗的位置,要连着它的交互一起看

我在一次弹窗验收里处理过“居中”的要求。实际检查下来,普通的短内容弹窗和需要输入的验证弹窗,不能只套同一条定位规则。

短提示卡片适合按设计居中;带 PIN、验证码或自定义数字键盘的面板,还要考虑键盘出现后的可用空间、操作按钮和底部安全距离。这些都需要对照对应的设计状态,不能只看一张没有键盘的截图。

也不能只挑一个弹窗修好,就认为同类弹窗全部正确。共享容器、内容高度和内部滚动规则,可能让它们在运行时表现不同。

我会至少检查:

  • 初次打开时的位置和尺寸。
  • 输入获得焦点、键盘出现后的布局。
  • 内容变长时是否能滚动,按钮是否仍然可达。
  • 关闭后再次打开是否稳定。
  • 浅色与暗色是否分别符合设计。

这里还有一个容易被忽略的细节:静态截图只能证明截图那一刻的样子。弹窗打开时有没有闪一下、从错误位置跳过来,需要录屏检查。低帧率录屏又可能漏掉短暂的首帧问题,不能拿它作“完全没有闪动”的证据。

五、不要为了一个页面,改掉整个项目的默认样式

AI 很容易找到一个看起来合理的共享组件,然后直接在那里改。

例如某个弹窗的背景色不对,共享主题里正好有一个接近的颜色变量。改完,这个弹窗对了,其他使用该变量的页面却一起变色。

我做过的一个处理是:保留原来的共享背景变量,为特定弹窗增加单独的语义变量。它多了一个名字,但把影响范围限定在了真正需要变化的地方。

组件默认样式也是一样。页面里的间距可能来自按钮内部,也可能来自弹窗外壳,或者外层布局。要先沿着真实组件路径查清楚,而不是在页面上不断追加覆盖。

“这个默认值在哪里生效、还有哪些页面依赖它”,是让 AI 修改样式前应该回答的问题。

六、我现在会先把任务缩小,再让 AI 写

以前比较容易把整页甚至整个设计文件交过去,希望 AI 一次理解所有上下文。后来发现,读得多不一定用得准。

我遇到过一次读取根节点返回大量元数据的情况。输出很长,却让真正要改的几个组件更难定位。后来改成先找目标区域,再逐个读取节点和截图,工作反而更清楚。

Figma 官方也建议 避免选择过大、过重的 Frame,把任务拆成组件或逻辑区域。

现在我的习惯是,一次处理一个可以完整验收的区域。先对齐弹窗本身,再处理输入状态;先确认字体和图标,再调整行间距。这样出了偏差,能知道它来自哪一步。

下面是一段可以按项目调整的任务描述示例:

目标:对齐指定 Figma 节点对应的移动端弹窗。

先读取该节点的设计信息和截图,再检查项目中的实际组件路径。
确认字体、图标资源、主题变量与组件默认间距。
优先复用已有组件;修改共享组件前,列出其他受影响入口。
不要凭截图猜测未提供的交互状态,也不要替换为近似图标。

修改后在目标设备尺寸上检查浅色、暗色、键盘弹出和重复打开。
报告已验证的状态,并明确哪些平台或状态尚未检查。

这段话并不能保证一次做对。它的作用是把任务变得可检查,让 AI 不能只交一份“看起来合理”的代码。

七、最后一轮检查,必须发生在运行画面上

我现在会把验收分成两部分。

代码检查负责语法、类型、组件使用和不必要的改动。视觉验收负责页面实际显示出来的效果。前者通过,不会自动推出后者通过。

截图比较时,先统一条件:目标平台、页面宽度、主题、数据和交互状态。React Native 的逻辑尺寸也要和截图的物理像素分清楚。两张图如果比例不同,仅凭肉眼比较间距很容易误判。

然后按问题类型逐轮检查:先看整体布局,再看文字,再看资源和颜色,最后看交互中的变化。不要一边换字体、一边缩图标、一边改容器高度,改完反而不知道哪一步起了作用。

图像叠加或差异图有助于发现位置偏差,但字体抗锯齿、阴影和平台渲染也会产生差异。它们适合帮助定位,不适合脱离实际画面,只凭一个差异百分比判定通过。

验收记录也应该具体一点:在哪个平台、什么尺寸、什么状态下检查过;还有哪些状态没有覆盖。我有过只完成 iOS 验收的情况,那就只能写 iOS 已检查,不能顺手把 Android 也算进去。

这比“已经和设计稿一致”更有用。后续再发现问题,可以判断是回归,还是原本就没有验证过。

写在最后

AI 读取 Figma,确实省掉了很多查参数、找资源和写初版页面的工作。我现在仍然大量使用它。

但页面像不像,常常取决于那些没有写在一行尺寸数据里的东西:字体实际有没有生效、图标画布里留了多少空白、组件带了什么默认样式、键盘出现后还剩多少空间。

这些问题需要到运行环境里看,也需要回到真实组件里查。

对我来说,工作方式最大的变化,是不再反复说“再像一点”,而是把偏差说明白:哪一行文字、哪个资源、哪个状态,与哪个节点不一致。每次改完,再去看同一组画面。

设计稿终于能被 AI 读懂了。下一步,是让它参与一轮有证据的实现和验收。