TL;DR
D2C 为 Design to Code 的缩写,意即设计稿转代码。
设计稿转代码是一个非常宽泛的描述,本文指的设计稿转代码,同时也是 Semi Design D2C 所提供的能力范围,主要集中在以下场景:
定位:前端工程师的辅助工具。
目标:加快前端工程师对照设计稿还原 UI 工作,降低人工写 Template Render 的成本。
使用 Semi D2C,3-5s,一键将设计稿转为可用代码
使用 DevMode,在 Figma 选中图层后,即可在右侧面板实时查看对应前端代码
直接上线,大概率不能。主要原因:设计稿能承载的信息是有限的,数据逻辑层在设计稿上是不易表达的。 绝大多数情况下,我们需要开发的都是带有实际业务逻辑 & 交互的界面,有非常多的逻辑,并非是纯展示类的 Landing Page。
对于这类页面,Figma 设计稿其实并不能完整表达我们的业务逻辑,非常多逻辑是通过 PRD 产品需求文档中的文本或者示意图承载的,例如条件判断语句 A 条件成立后,B 模块才展现,A 的值修改后 B 的值跟随联动等,这些逻辑的表达根据不同设计师习惯,风格形式不一,无法做标准化解析。
因此通过设计稿转出的代码距离实际线上代码是有一定区别的,D2C 转不出设计稿上未表达的逻辑,绝大部分场景下我们依然需要一定的二次编辑。(主要是添加数据交互逻辑)
但通过 D2C 转出的样式层 JSX + CSS,基本可以做到不用额外大幅改动。大部分情况下,我们只需要加上交互数据逻辑,即可达到上线标准。
前端工程师拿到设计稿后,打开 Semi Figma D2C 插件,选中图层即可在右侧 DevMode 的面板中,实时预览对应的 JSX + CSS 代码,复制所需代码至项目仓库中或通过插件直接写入本地仓库,直接使用。
亦可跳转至 Codesandbox 中进行调试或编辑复制。
D2C 支持多种格式的产物输出,除了常规的 JSX + SCSS、JSX + Tailwind、JSX + Emotion 外,我们还提供了 JSON Schema 格式导出,完整描述了内容及布局。
lowcode 搭建平台可消费 Schema ,进行后续的开发流程。
Semi D2C 支持了通过转码插件实现自定义转码产物(https://semi.design/code/zh-CN/d2c/transform-plugin),即你可以通过编写一个自定义的 AST Plugin,对 Semi D2C 的原始出码产物(JSX/CSS Code 或 JSON Schema)进行二次编辑,可用于添加自定义的业务逻辑,例如:
在部分交互范式非常固定的场景下,用户借助该方案,可以自行往 GUI 层添加固定的业务逻辑后,是可以做到产物直接上线的。
过往业界的 D2C 方案,更多集中在 C 端场景。B 端 与 C 端做设计稿转代码的关键区别是什么呢?
Semi 作为中后台场景的设计系统,能力必须满足 B 端场景的基线,才能真实落地业务。以下有三点是 Semi D2C 与其他方案最大的区别:
Semi D2C 方案提供了精准到组件级 props 的识别能力,对全部 Semi 基础组件的全部设计形态,都提供了识别能力,不需要研发手动对组件进行标注。
换句话说,设计师使用这套 UI Kit 搭建出的设计稿,设计稿上的组件全部都能被转移成真实的组件代码,不再仅仅是渲染后跟设计稿长得一样的无意义 div。
业界也有一些 D2C 工具也提供了强大的组件标注能力,但由于没有与 Design System 做很好的打通,所以在实际的使用中需要人工将组件以及组件属性进行标注,依然存在一定的使用成本。同时由于缺乏对底层组件库的掌控以及场景建设,对使用场景中有较多限制。
我们在 2021 ~ 2022 年调研过 Figma 平台上公开可用的 C2D 工具,它们基本都选择了将组件作为一个实例绘制在画布上,之后无论是创建实例还是切换组件形态都需要通过一个 Figma 插件操作。
然而,在实际的设计流程中,设计师可能并不习惯打开一个插件创建和更新组件,这会影响设计师的使用效率,同时实例也并非是设计师习惯的消费方式,他们更习惯于通过 Figma Variant 变体的方式切换组件形态。
设计师使用 Figma Variant 切换组件形态的过程
Semi 提供的方案允许设计师继续通过 Figma 变体的方式使用组件,与原有的设计流程一致。对设计师而言,无需通过额外安装插件操作,与原有习惯保持一致,如以往般高效。
C2D 并非 Semi 首创的生产方式,在之前业内已经有一些先驱产品(如 story.to.design,anima)进行过探索,他们支持导入第三方组件库转为设计组件。
但这类通用型的方案,在抖音团队的应用场景中,无法完全满足我们的诉求。主要存在以下方面的局限:
与通用型方案相比,Semi 由于自身掌控底层组件库资产,可针对性做迭代适配修改。对 Semi 组件的支持天然可以做到更全,更合理,我们 C2D 的产物,可以产出更合理的图层结构,以及 AutoLayout 支持,同时还能兼顾主题定制等业务真实场景。设计师使用成本不会有明显变化。
从需求设计稿到研发实现 UI 还原过程,无论是研发,还是设计角色,都存在一些效率较为低下的环节,我们认为可以通过研发工具、设计工具的建设,提升双角色的效率。
与传统的主题商店不同,主题包在 Semi Design 体系内,除了会作为 npm 包供研发侧在代码仓库中消费,还需要在 Figma 中被设计师进行消费。我们打造了一个 DSM 设计工具用于在 Figma 、Npm 间双向同步主题设置,使得设计师可以在最熟悉的平台:Figma 上进行样式变更。但即使我们通过 DSM Plugin 实现了全局级别 Design Token 的双向同步写入,在落地上依然遇到了一些限制。
由于原人工方式做的 UI Kit 中,组件级的 Design Token 在原图层中无相关表达声明,只有通过 C2D 方式重新生成 UI Kit,才可实现组件级的 Token 的刷入支持。我们才能做到在 Figma 端完美实现主题刷入。
因此 我们希望通过 D2C(Design to Code)解决 1,2 的问题,同时需要借助 C2D(Code to Design)解决 2,3,4 的问题。
Semi D2C 的整体探索历程,自 21 年启动,陆续经过了近两年的持续建设。由于整体流程有非常多的细节问题需要处理,我们选择了渐进升级的路线。
我们的 MVP 版本,在不包含组件的场景例如 Landing Page 类业务中,跑通了核心的布局还原逻辑,实现了将 Figma 元素到 React 代码的转换,实现了常规 Frame 等元素的 D2C 支持。
随后在这基础上,我们开始进行 C2D2C 方案的验证,从中选择了 20+高频组件,跑通了组件级 props 识别这一核心能力。
而后续 23 年的建设则主要围绕 1 扩大支持的 UI 组件范围 2. 提升开发者体验 两点展开。我们陆续完善了所有组件的识别,支持了 Semi 的主题功能,提供更多类型的产物输出如 Schema 、Tailwind,以便开发者可利用 D2C 工具与其他自建的工具平台打通,同时也开始提供系统性的技术方案去支持第三方 ui library 的接入。
🎓 本质上,无论是 C2D 还是 D2C,都属于结构化信息的提取与转换。
C2D Figma 组件绘制, Code to Design 的核心工作是在 Web 环境中渲染组件,获取真实的 DOM 节点信息,通过 Figma 插件 API 在 Figma 环境中重新绘制成对应图层。然后重复这一过程,通过预先穷举 Semi 组件的所有 UI 参数(影响 UI 的组件 API),在 Figma 中得到组件的所有变体。
📌 整体流程:React Component -> HTML DOM + CSS -> Figma Layer -> Publish As Figma Component。
D2C 流程
D2C Semi 组件识别,该能力主要借助了 Code to Design 过程中在 Figma 组件变体中进行预先埋点, 因为 Figma 的 UI 资产完全通过代码自动生产,因此可以在 C2D 过程中对几千个组件变体预先埋下组件信息,从而在 D2C 时不但可以确定设计稿中使用了哪个组件,同时能精准确定组件需要传递的参数。
📌 整体流程:Figma Component + Figma NodeInfo -> HTML + CSS。
C2D 要达到可用准入标准,必须具备的三个基础核心能力如下:Auto layout、组件嵌套和合适的数量。
有 auto layout 能力的 Button
在 C2D 环节,需要将 Semi Design 组件的 DOM 转换成 Figma 的变体,上述三条标准均为硬性指标。但由于浏览器和 Figma 这两个宿主环境不一致,我们在实践过程中遇到了诸多难题,比如 CSS 与 Figma 样式差异过大、变体图层过多突破宿主内存限制、准确还原 AutoLayout 自动布局难等,一些比较代表性的问题如下:
D2C 要达到生产环境可用,需要解决以下几个核心问题:
由于渲染引擎不同,Figma 画布中的布局与传统的 HTML CSS 支持的布局有着较大差异。
页面的常见布局有 flex 布局和 absolute 布局,在设计稿中图层之间的关系一般是绝对定位,那么 D2C 把它直接转为绝对布局是最直接方式,但绝对定位不利于二次修改,且在不同屏幕上的适配性极差,代码实用性上存在问题。
为了更贴合人工书写方式,我们需要有更智能的还原规则。一些例子,如:
调整最外层宽度,左侧区块可以自动填充容器。
转码时通过蓝色线框提示 auto wrapper 的位置。
转码时,会自动将区块进行分组,并转换为 flex 布局。蓝色线框是转码时区块的划分位置。
转码后,可以看到把水平方向上的区块划分为了一个大区块,并使用了 flex 布局。
除上述例子外,还有更多实际场景中的复杂例子,篇幅所限不一一赘述。
在中后台场景的设计稿转代码识别中,支持组件粒度的识别是能否应用于生产环境的决定性因素。如果页面中有具体的 UI 组件,而转出来的代码仅仅是一堆 div + style,并没有实际用到从 npm import 的组件模块,那这些代码依然是不可用的,研发需要花费大量时间去进行替换。
如何将 Figma 组件精准地转化为 React 组件是我们首先要解决的问题。调研过后,我们发现业界对组件的识别目前有通过人工标注、CV 识别的方式,但都有一定的局限性。
我们需要有一种使用成本更低 、精准度更高的组件识别方式。最后我们选择了 C2D2C(见上方“核心实现原理简介”章节)
将设计组件识别为代码组件
在解决了如何将 Figma Component 转换成 React Component 后,我们仍面临一个问题:如何实现组件自定义内容的识别?
组件自定义内容是指在组件内可以修改并识别为 props 属性的地方,例如 Button 的文本、Form 表单的 Title 标题、Table 表格的 Cell 单元格等。设计师在画稿时常会修改这些地方的内容,D2C 时需要将这一部分识别为 ReactNode 类型的 prop(在 React 中)。为了实现这个目标,我们需要找到对应图层与组件属性的关系,并把它的内容进行识别,然后在出码时将自定义内容作为组件属性的一部分。
由于我们拥有 Semi UI 底层资产,我们可以通过修改组件实现,在 DOM 上以 attribute 的方式去承载映射关系。
由于图层结构由设计师生产,而代码由研发工程师生产。两个角色之间的思维方式不同,决定了产物的组织形式上可能存在天然差异。
而 C2D / D2C 的本质是结构化信息的互相转换,设计侧的组织不一定符合研发的习惯。所以我们需要做更多智能的处理判断,使得出码风格更像人工编写,保证代码的可维护性。
在这点上,我们目前已做了一些非常基础的工作:CSS 重复样式合并、CSS 类名优化、表格内联样式优化。
下一步准备做什么:做更智能的公共变量提取、同类组件聚合、样式聚合;根据使用场景预判更多示例代码等。
主要体现在 UED 角色:
主要体现在前端工程师角色上:
提升研发生产效率,增大需求吞吐,较少反复验收导致的耗时。
一致性
一般不会输出绝对布局产物,D2C 会做适当优化。具体细节,参考“实现难点 - D2C 的难点 - 如何准确将页面布局还原”章节。
中后台的设计稿,对于组件级的 props 识别要求非常高。不仅仅是识别出它是一个什么组件,这个组件在当前设计状态下对应的 code props 也得还原,才能真实地用起来。如果仅仅将其还原为 div + css,或者将不同形态下的组件,都统一当做一个形态去还原,研发依然需要做大量二次编辑的工作,实用性无法满足业务诉求。
因此,准确度是对 D2C 而言至关重要的核心能力。而视觉识别的路线,要想达到较高的准确率,成本非常高,训练过程可控性较低,精准度不够会导致二次修改成本剧增,难以在生产环境落地。
此外,视觉识别或者说 image2Code 的路线,更多的限制是,它对于 Design System 的承载能力并不强。对于形态相近的元素的区分能力弱,例如 Select 组件 与 TreeSelect 组件,在设计稿上,外表形态都相近,仅靠视觉形态无法做有效区分,但实际代码差别较大。
C2D2C 本质上,相当于一个精确度 100%的模型,但是实现过程都相对透明可调试,成本可接受。
对于品牌体验有强定制诉求的场景,C2D2C 相比视觉识别,更有优势,能更好地与设计规范及结合。
实现通用型的 D2C 是我们的长期目标。当前 D2C 对于 Semi 体系的基础组件完善程度已经较高。我们 2023 Q3 建设目标,就是围绕自定义组件、第三方 Design System 的 D2C 支持开展工作。
有两种方式可以对 非 Semi Design 的 UI 资产进行接入:
两种方式有不同的使用场景,当前我们已经在多套非 Semi 系的 library 上 进行了接入验证。更多技术细节可查阅:Semi D2C 第三方组件库接入文档(https://bytedance.feishu.cn/wiki/MQZ1wsHaIiyA5ukz0qMcL53en1g)
人工标注方案主要的流程如下:在 Figma 中通过使用 Semi D2C 插件提供的标记组件库功能,对已存在的 Figma Variant 组件集进行标注生产。标记过程需要研发同学实现 metaDataFactory
方法,声明 Figma 图层或 Variant Property 与 API 之间的映射关系。
对于其他业务而言,我们一般推荐优先使用标注方式接入,因为:
参考上述“实现难点 - C2D 的难点”章节,C2D 设计组件要达到满足设计师的使用习惯,有非常多的过程需要人工处理,入手成本和适配成本都很高,无法简单适配一套第三方组件库(这也是目前设计师没法直接使用 Figma 社区内现有的一些通用型 C2D 方案的主要阻塞点)。
这里同步一个数据供大家参考:Semi C2D 已支持全量 Semi UI 组件。在前置流程已跑通的情况下,其中每个复杂组件的 C2D 生产过程需要研发 6 人日,中等复杂组件 4 人日,简单组件 2 人日。另外也需要设计的验收成本,每个组件预计 1 ~ 2h。
在当前,这一方式的成本仍然明显高于标注的方式。因此对于非强诉求的场景,我们一般不推荐以这种方式进行。
Auto layout 是设计组件可用性标准之一,简单来讲就是 Figma 的弹性布局,可以让容器适应文本的宽度,或让子图层填充父图层的宽度。如果设计组件不支持弹性布局,例如在 Input 里如果没有 auto layout,修改完文本后,还需要手动调整子级相对父级的位置;或者外层容器调整宽度后,子级位置没有跟随容器变化。可以想象,没有 auto layout,设计组件一次修改需要改动多个地方,对于设计师来说是比较繁琐的。
可以说,如果不支持 AutoLayout ,对设计师而言,这套 UI Kit 基本等于不可用。
首先,交互范式有可能发生改变,未来不一定仍是 GUI 为主,可能是 LUI,设计系统未来的发展可能是不定的。但 LUI 是否在所有场景下,都能比 GUI 有更高的交互效率,不一定。假设人机交互范式仍维持现有的模式的前提下,使用设计系统搭建企业级应用,在效率、体验上仍然具有较高的价值。
如果仍然以现有的 Design System 在设计、研发链路的使用习惯去看。未来若随着大模型能力的提升,当前的 C2D、 标记组件库这些成本较高的环节都有可能得到进一步简化,甚至直接省掉。
但当前而言,AI 对于设计系统的支持,要提升精准度,需要做较多的调教,准确度是最大的问题,目前暂时没出现成本可接受且易用程度高的方案。从 0 到 1,完全由 AI 去做识别,当前的可落地性不强,成本仍然较高。
前面提到,D2C 的另一个难点是使得转出的代码更像人类工程师书写,我们可以使用 AI 去加速改进这一过程。目前仍然处于内部 Demo 探索阶段,在 Semi 内暂时未有成熟的实践结论,此处暂不展开。
[1]
Semi D2C 官方站点: https://semi.design/code
[2]
Semi D2C Figma 插件: https://www.figma.com/community/plugin/1166339852662786534
[3]
Semi Github 主仓库: https://github.com/DouyinFE/semi-design
[4]
Semi D2C 第三方组件库接入文档: https://bytedance.feishu.cn/wiki/MQZ1wsHaIiyA5ukz0qMcL53en1g
[5]
Figma AutoLayout 说明: https://help.figma.com/hc/en-us/articles/5731482952599-Using-auto-layout
往期推荐