本文作者:魏慷

本文从 UI 研发的痛点出发,谈一谈网易云音乐在解决 UI 研发效率上的思考和实践,包括「海豹 D2C」产品研发中的方案设计与技术挑战,并介绍如何使用「海豹 D2C」实现高效的 UI 研发。
背景
在产品交付链路中,UI 研发的高效与否直接关系到产品的上线节奏。在网易云音乐,我们发现,随着业务的发展以及技术体系的升级和迭代,UI 的研发过程也渐渐暴露出了一些问题。

常规的一次产品交付链路中,涉及到 UI 研发的过程主要有:
设计师使用 UI 设计软件进行设计,将设计稿交付给研发工程师;研发工程师手动将设计稿中的内容还原为代码,并交给设计师走查;接着,设计师提出修改意见,再次由研发工程师修改代码。待走查完毕后,方可发布项目。
在这个过程中,会存在这些情况:
- 设计稿本身无法完整描述设计意图,需要通过标注另行说明;
- 研发工程师对于设计软件不熟悉,遗漏了设计稿中的一些关键点没有还原到代码中;
- 因为项目时间紧任务重,研发工程师赶工式开发,导致 UI 还原度低。
这些问题导致在 UI 还原为代码的过程中,设计师需要通过标注表达设计意图,在走查过程中效率低,一般需要重复多次走查,方能让研发工程师修复所有问题;
另外,对于设计师而言,由于彼此的分工不同以及一些历史债务,导致设计师的设计工具并不统一,像 Figma / MasterGo / PhotoShop 都有在使用。
而对于研发工程师来说,例如在网易云音乐,为了支撑业务的快速发展,存在着较为多样化的 UI 技术体系,涉及到 H5、React Native、动态 DSL、动态图片等。为了应对不同的业务场景,研发工程师需要学习多种技术体系和平台下的 UI 还原。
如果我们对上面流程中的问题进行总结,就会发现网易云音乐 UI 研发的痛点主要为:
- 沟通成本比较大
- 工作效率比较低
具体而言,研发链路长就会导致沟通成本大,手写代码还原 UI、UI 还原度低、技术体系多样化导致工作效率低,而设计工具的多样化、UI 走查的低效既会导致沟通成本大,也会导致工作效率比较低。

在此背景下,我们希望有一个工具来代替前端人肉还原 UI,从而从繁冗的设计稿还原工作中解放出来。 我们将它命名为「海豹 D2C」(Design to Code),它的定位是一站式的智能 UI 研发解决方案,根据设计稿一键智能生成代码。
我们期望 D2C 的还原度是 99.9% , 相比于人肉还原的代码要更精准。此外,它还要去智能分析设计意图。这也有望让设计稿的标注和走查这两个流程节省下来,从而去节省开发和设计师间的沟通成本。
应用了「海豹 D2C」的新流程,我们希望,对于设计师,带来的收益有:
- 设计提效,让设计师免除了繁琐的标注工作,稿子画完即可交付
- 沟通降本,让设计师省下了 UI 走查的时间,大大降低了与前端的沟通成本
对研发的收益,我们希望能够达成:
- 研发提效,让机器替代人肉还原 UI,只需要不到 10 分钟即可搞定一张页面
- 沟通降本,免除了因还原度不达标而与设计师反复沟通的问题。
产品设计
通用性
我们希望「海豹 D2C」产品,它应当具备足够的通用性:

输入阶段的通用性要求
-
支持常用的设计工具
需要支持包括 MasterGo, Figma, PhotoShop, Sketch 等在内的设计工具
-
不对设计稿做要求
在我们的前期调研中发现,设计师都有自己的一套设计风格,这个风格也包括了对 UI 设计软件的使用习惯上。由于使用 D2C 产品的用户往往是开发,他们无法要求设计师一定要按照某套规范来作图,如果强行对设计稿规范做要求,势必会导致产品难以推广落地,因为它不是一套通用的方案。
D2C 生成阶段的通用性要求
-
组件识别支持任意组件库
优先支持网易云音乐使用的海豚组件库。但是,对于组件的识别应当是通用方案,可以运用在任何组件库上。
-
只做UI还原,不做逻辑识别
在 UI 设计软件上,目前还很难表达逻辑、动画等等内容,D2C 的产物必然是静态页面。如果强行在 D2C 阶段增加对逻辑绑定等操作,一是不具备通用性 ,二是势必让产品操作流程变复杂 。专业工作交给专业工具,我相信对于逻辑绑定这部分内容,应该在一个脱离 UI 设计软件的独立平台做会更方便,例如在网易云音乐,就有 Tango 低代码平台 可以做这样的事情。
输出阶段的通用性要求
-
支持多种技术体系和搭建平台
要支持最常用的技术栈,并且应当有一个通用的、开放的方案,可以对接到搭建平台。也就是说,只要愿意,任意的搭建平台都可以消费「海豹 D2C」的产物。
由此,我们设计出「海豹 D2C」整体流程。经过我们的反复迭代,目前它的流程是这样的:

在设计工具方面,支持目前广泛使用的 MasterGo, Figma, PhotoShop, Sketch 等多种格式的设计稿。
由于 UI 应用场景的不同,在技术体系上,网易云音乐主要涉及了 React, React Native 等多种技术栈,「海豹 D2C」需要支持这些类型代码的交付;
另外,网易云音乐也有通过「灵渠」DSL 搭建页面,和「云雀创意中心」动态合图的方式进行搭建交付,为此,「海豹 D2C」需要提供对接的开放能力,以无缝对接这些搭建平台,实现设计稿一键生成搭建物料。
对于这些通用性要求要如何实现,我们会在后面再做详细介绍。
无损的信息提取
D2C 的本质是从设计稿中进行信息提取,并转换成代码的过程。
之前有一些 D2C 产品,包括微软的开源方案,可以基于图像识别做信息提取。它的好处是不依赖设计稿,但是缺点也很明显:

- 图层边缘信息易受其他图层干扰;
- 矢量数据丢失;
- 布局结构难做等。
而假如使用的 UI 设计软件提供的 Open API,我们可以确保拿到所有的原始数据都是无损!通过图层本身信息的无损提取,做到 0.0001 px 精度还原。此外,UI 设计软件还提供了这些有效信息来帮助我们识别设计意图,生成更加友好的代码:

- 布局结构,例如对于自动布局、约束的描述;
- 图层的分组信息;
- 组件信息;
- token 信息。
很简单的道理,当我们在 PhotoShop 中保存 PSD 格式文件,那么下次打开该文件仍然可以继续编辑,但是对于一张导出的 PNG 图片,想要二次编辑就会比较犯难。设计软件本身包含的结构化信息,一定是大于一张二维图片的。
多软件适配
使用 Open API 的唯一缺点,就是每个 UI 设计软件都有自己的一套标准,我们需要分别去适配。
我们最终考虑去支持 Figma Plugin API 和 MasterGo Plugin API,也就是说「海豹 D2C」是以插件的形式运行在 Figma 和 MasterGo 中,这是一个运行在浏览器中的 iframe 页面,同时利用 Plugin API 与 UI 设计软件进行交互。
对于网易来说,除了 Figma, MasterGo,常用的设计软件还包括 PhotoShop, 早期还有 Sketch。由于 MasterGo 支持导入 Sketch, XD 等格式的设计稿。我们只要支持 MasterGo,无需额外开发也就间接也支持了这些设计稿。对于 PhotoShop 格式的设计稿,我们也间接进行了支持,实现思路如下:
Adobe XD (也可称为 Experience Design) 是由 Adobe 公司开发并发行的一款 UI 设计软件,尽管它有点冷门并且已处于维护模式,但它支持打开 PhotoShop 的 PSD 文件并保存为 XD 文件。而 MasterGo 恰恰又支持导入 XD 文件。最重要的是,XD 与 PhotoShop 同属于 Adobe 公司开发,可以保证在 PSD 文件转换为 XD 文件过程中的还原度。
所以,到这里解法就很清晰了,我们并不是直接支持 PhotoShop,而是采用了曲线救国的办法:先将 PSD 转成 XD,XD 转 MasterGo,然后由 D2C 消费 MasterGo 设计稿。「海豹 D2C」对 PhotoShop 的支持,不仅实现成本低,而且还原度也能得到保证。

最终下来,我们只要让我们的插件适配 Figma 和 MasterGo 就可以了。他们的 Plugin API 高度相似,这使我们节省了不少开发成本,往往只需要开发好一端的插件,再去适配另外一端的插件即可。当然,高度相似不代表完全一致,特别是一些细节实现上,总会有让人意想不到的差别。
中间产物 Uniform UI Schema
为了实现兼容多种设计稿和代码模式,我们制定了一个 D2C 中间产物的规范,叫 Uniform UI Schema。通过 Uniform UI Schema,就可以在不同格式的设计稿和不同的代码模式之间实现统一。比如,对于 Figma 设计稿而言,就可以提供一个 Figma Transformer,将其转换成 Uniform UI Schema,然后搭配不同的 Code Generator,便可以生成不同的代码。
Schema 统一方案,标准开放,支持流转到其他平台,支持多种代码,且可以快速对接支持新框架。

例如,在网易云音乐我们主要使用 React 技术栈,一开始没有支持 Vue。但在网易集团,存在其他事业部以 Vue 作为主要开发框架,我们便快速支持了 Vue 代码的生成,在这个过程中,并不是从 Figma/MasterGo 使用 Plugin API 信息提取到 Vue 代码输出的完全重写,而是 Uniform UI Schema 到 Vue 代码的转换,总体仅消耗 1 人日时间。
到后来,我们甚至提出了插件中的插件的概念------微插件。作为「海豹 D2C」插件的使用者,也可以参与到输出代码产物的过程中,通过开发一个微插件,介入到 Uniform UI Schema 到代码转换的过程中,从而产出「海豹 D2C」本体未支持的框架。
所见即所得
我们也可以基于 Uniform UI Schema 快速输出 HTML Code。由于 HTML Code 相比于 React 代码,可以不经过编译在浏览器中更快打开,适合作为我们 D2C 生成效果的预览。有什么好处呢?
-
相比于常规的流程,我们从设计稿生成代码,最理想的情况,开发需要使用像 VS Code 这样的 IDE 将代码复制过去,编译运行,最终在浏览器中预览效果。如果因为设计稿本身的问题导致生成的代码有瑕疵,此时就要修改设计稿规避这种问题,就需要重新走 D2C 流程,这个过程略显繁琐。
-
另外,在 D2C 这一新鲜事物刚出来的时候,大家可能还是会持怀疑的态度,担心生成的代码还原度不好。如果在打开插件时,马上就能看到最终生成的效果预览,就可以根据生成的质量,再决定是否导出代码。

因此,在我们的「海豹 D2C」插件的首页,我们提供了预览图,这个预览图并不是基于设计稿简单的导出图片,而是实打实通过我们的 D2C 出码生成的真实 HTML,可以直接看到 D2C 出码后的效果。不管效果是好还是不好,一目了然。

设计稿优化
前面说到,我们不对设计稿规范做要求。那么会有哪些问题呢?这里简单举几点:

- 设计稿中存在无用图层,例如已经隐藏,无实际有效填充,未在可视区域内等。这样导致生成的代码也包含了冗余元素。
- 图片未指定导出的格式,比如是生成 PNG 格式的图片,还是生成 SVG 格式的图片更合理。这在代码生成时无法推断图片格式。
- 还有一些图层适合作为整体导出图片,但是没有设置导出,例如复杂的背景元素。在代码生成时,可能无法获知要整体导出,导致生成的代码过于复杂。
- 部分容器适合使用响应式布局,但是设计稿中并没有设置。导致生成的代码无法响应不同设备尺寸,需要开发再去调整。
- 设计稿未按照逻辑进行成组,通过父-子的图层关系结构去描述这种逻辑关系,而是一个扁平的图层结构。这导出生成的代码可读性不强,也会影响相对布局的定位。
使用「海豹 D2C」插件的是我们的前端开发工程师,不会那么熟悉设计软件,上手学习需要一定的时间成本。那么要如何处理这些问题,让生成的代码符合我们的预期呢?我们先看下其他 D2C 产品是怎么处理的。
-
手动优化
以 Figma Dev 模式下提供的 Figma To Code 为代表,原样还原设计稿中的信息,输出代码一定符合预期。如果设计稿有一些问题影响了代码的生成,就需要进行手动优化,优化的效果会保存在设计稿中 。问题在于手动优化比较繁琐 、耗时 ,并且有一定的学习成本。
-
自动优化
常见的 D2C 产品,往往会对设计稿做自动识别,无需人工介入 。但完全不需要人工的问题就是,可能遗漏需要设置的内容 ,同时误设置不需要的内容。
「海豹 D2C」提出了智能识别 的概念。在自动识别的基础上,我们加入了人工介入审核内容,避免错误设置或误设置不需要的内容。当然了,对于遗漏设置的内容,我们还是支持手动优化的。
智能识别是我们的默认模式,如果觉得人工确认过于麻烦,你还是可以选择快速生成模式来生效自动识别。

通过智能识别,我们可以做到:

- 设计稿中存在无用图层:我们能够识别到这些图层并做移除;
- 图层未指定导出图片或适合作为整体导出图片,但是没有设置导出:根据图层内容推荐导出图片,可在导出设置中生效;
- 适合使用响应式布局,但是设计稿中并没有设置:我们能够识别到这些图层并做相应的设置;
- 设计稿未按照逻辑进行成组:调整图层,使他们按照逻辑形成父-子的图层关系结构。
基于此,我们的开发即使不熟悉设计软件的使用,也可以在「海豹 D2C」的引导下,对设计稿进行优化。

技术挑战
C2D2C 组件识别
网易云音乐有两种典型的页面类型:
- 一种是活动页面,它创意性强,没有固定的设计规范,比如恋爱人格测试活动,摸鱼计算器活动等等。D2C 在还原这类页面时,无需识别它是具体哪个组件库;
- 另一种是产品功能页面,它强调 UI 的一致性,有固定的设计规范和交互逻辑,所以需要识别组件并将其转换为对组件库中组件的引用。
而业界的组件识别方案一般有两种思路:
- 一种直接在设计稿上进行人工标注,它的优势是技术实现成本低,但是缺点是工作量会转移到设计师,标注成本比较大。
- 另一种思路则是利用 CV 技术,也就是利用计算机视觉相关的图像识别算法对组件进行识别,它的优势是无需人工标注,模型自动识别组件,缺点是模型的训练和更新成本比较大,ROI 比较低。
这两种方法都不适合网易云音乐的实际情况,于是我们探索出了基于 C2D2C 的组件识别方案 。它的优势是无需人工标注 即可识别组件,而且技术实现成本低 ,ROI 比较高,它的缺点是组件库有一定的接入成本,但是我们也提供了工程化的解决方案。
它的具体思路是,我们将组件的代码库,通过 C2D 技术,也就是 Code to Design,将其转换成设计软件的 Library,并同步诸如组件相关的元数据。这样设计师在使用 Library 的时候,通过元数据就自动实现了对组件的标注,最后在 D2C 的过程中将就会被识别出来。

具体而言,就是将 HTML 的元素,比如对于 div 标签、p 标签、svg 标签,可以依次映射成 Figma 的 Frame 节点、文字节点和矢量节点。按照其在 React 组件库中的组件名称,到 Figma 中,在 Library 中实现相应的组件。

这里截图显示的就是我们通过 C2D 技术生成的 Library,以 Button 为例,当设计师使用了 Library 中的 Button 后,借助组件变体和属性功能,便可以像使用 React 组件一样,随意更改组件的属性,并且能够在 D2C 阶段通过元数据识别出来。
在做 C2D 的时候,为什么要在图层中绑定元数据呢?其实就是用来做物料识别的。原理并不复杂,基于 C2D 的产出的设计稿,我们会解析设计图层和元数据,同时进行物料的识别,最后还原成代码。
比如,对于 Button 而言,C2D 在生成设计稿时,会为图层绑定组件的元数据,包括组件名、组件 Props,API 文档等,D2C 时,直接读取组件元数据,翻译成代码即可,其间不会丢失任何的设计细节。

布局优化
层级调整
部分设计师习惯采用扁平的图层结构,未按照业务逻辑进行良好的图层分组。如果直接基于此生成代码,尽管还原度也能够得到保障,但最终代码的可读性比较差 ,二次编辑也较为困难。
为了能够生成可读性好、能二次开发的代码,势必要对布局进行优化。而布局优化的本质就是将 扁平的结构 转换成 行列嵌套 结构。
例如下图中,左下角有个设计稿,包含 ABCD 四个节点,如果不进行布局优化,那么整个页面将是一个扁平的结构,生成的是绝对定位的代码。虽然还原度能够保证,但是可读性比较差。

而布局优化的过程,则是对 ABCD 进行分组,首先将页面分为 ABC 和 D 两行,然后将 ABC 分为 A 和 BC 两列,最后将 BC 分为 B 和 C 两行。
分好组后,通过新增三个布局容器,形成行列嵌套结构,这样最终生成的代码将符合开发者的直觉,具备较好的可读性。
不难发现,做布局优化,其实就是在做行列分割,人眼一眼就能看出来需要这么分割,那对程序来说,具体要如何实现呢?
我们独创了行列分割算法(专利公布号:CN116861853A)。整个流程,大致可以分为以下 5 步。

-
首先,我们需要获取到待处理的节点坐标;
-
然后,进行节点关系的处理:判断它们是处于包含、还是相交还是相离关系
- 包含关系:将被包含的节点作为其子节点处理。
- 相交关系:两者看做一个整体,且其中一个相对于整体作绝对定位处理。
- 相离关系:不做额外处理。
-
节点关系处理完成后,则是做二维空间投影,找到行列分割的依据。比如,通过纵向投影,我们就知道了 ABC 和 D 是属于不同的两行,通过横向投影,我们就知道了 A 和 BC 属于不同的两列。
-
接下就是做行列分割了,其主要工作就是依据二维投影信息,添加布局节点,进行分组。
-
最后就是样式的计算,生成包括 Flex 布局、绝对定位以及 Margin 偏移量等。
自动布局的识别
在层级调整的基础上,我们还需要识别自动布局。自动布局转换为代码后,其实就是 Flex Box。通过 Flex Box,就能够让页面实现响应式,例如在屏幕变宽以后,一些元素弹性放大,或者是选择不放大,但是一行内能够容纳更多的元素。
那么如何识别自动布局呢?我们大胆猜测,自动布局往往是运用在由相似元素组成的列表。那么具体的实现算法就变成:

-
识别相似元素,可以从尺寸、描边、背景填充、文本大小等角度去计算相似度,而文本的内容、图片的内容则认为是合理的差异,不应当参与计算。并且在实际的识别中,还需要对元素的子元素进行遍历,也做一遍相似度的计算;
-
可信度计算:由于这些元素最终组成了列表,还需要分析下元素所在的容器是否是一个正常的列表形态,包括元素相似度、元素间距、元素对齐方式等。如果元素间距完全不一致或者元素未按照某些方式对齐,则可信度较低,不像是一个列表;
-
识别自动布局中,元素的尺寸约束:约束主要分为三种,包括
- 固定值 (Fixed):调整父框架大小时,如果我们不希望元素尺寸发生变化,可以选择这个来保持固定的尺寸;
- 填充容器 (Fill):自动调整尺寸,使之填充父框架的剩余可用空间;
- 拥抱内容 (Hug):当子元素也是自动布局框架,或者是一个文本类型的图层时,允许设置为Hug。对于文本类型,其拥抱内容的方法是,保持尽可能小的尺寸将其中的文本完整显示。
我们可以分析现有设计稿的设计意图,选择合适的约束。比如,目前元素总是占据父元素 100% 的宽度,可以认为是一个 Fill 的约束。但如果它是一个文本节点,则可以更正为 Hug 的约束。
当然,智能识别也可能无法准确识别出约束时,这时候就需要用户自己做决定了。
如何让代码和手写的一样
D2C 直接导出的代码,有一些问题。比如:
- className 使用无意义的数字,这会导致代码的可读性变差
- 重复样式多,未合并,当后期手工调整一些样式时,需要搜索到这多个重复样式分别修改,不太方便
className 语义化
对于 className,我们希望进行语义化,我们想到了使用 ChatGPT 来实现。

只要将「海豹 D2C」生成的代码,交给 ChatGPT,并通过 prompt 告知需要对 HTML 中的 className 进行语义化即可。当然,如果需要更好的效果,需要将尽量多的图层信息,也交给 ChatGPT 进行分析。可以看下生成的效果,还是比较符合预期的:

基于此,className 从简单的以图层 ID 得到,变成了由更具语义化的词语组成,提升了代码的可读性,也有利于我们对代码进行二次修改。
合并重复样式
对于重复样式,我们也有尝试过使用 ChatGPT 进行优化,但是效果不太理想。
好在对于重复样式的识别,主观性其实没有那么强,即使不借助 AI,也可以提炼下算法来实现。一种实现思路是这样的:

对兄弟节点本身的样式(不包括他们的子节点)进行统计,如果重复样式的数量比较多,对这些样式合并到同一个选择器中。
如果发现有一些兄弟节点的样式高度一致,那么再遍历他们的子节点,注意应该是相同位置,也就是相同数组索引的子元素,也进行统计,按照前面的流程再走一遍,将相同的样式合并到同一个选择器中。
总结与展望
目前,「海豹 D2C」已在网易云音乐绝大多数业务场景中落地,对于我们的 UI 设计稿还原为代码,能够做到 99% 的准确度。在还原度 、生成速度 、易用性 、平台支持度 等方面,相比于业界其他 D2C 产品,具备一定优势;对于我们的研发工程师在 UI 还原方面,平均能够做到 30% 以上的提效。
由于 D2C 技术方案本身足够通用,我们的插件适用于任意场景的设计稿,「海豹 D2C」已在 Figma, MasterGo 社区中发布,已累计协助生成数千个页面。值得一提的是,「海豹 D2C」是MasterGo 插件社区中第一款也是目前唯一一款 D2C 产品。
在未来,我们会重点提升「海豹 D2C」对于自适应布局识别与还原的支持。对应的解决方案,其实在本文也已经做过介绍,已在内测中,不久就可以和大家见面。
我们也会考虑借助大模型技术在例如层级调整、组件识别、逻辑意图识别等方面让「海豹 D2C」达到更高的智能化水平。
此外,当前「海豹 D2C」解决的问题,本质上是 UI 研发过程中的效率问题和沟通问题,但是却没有触及到 UI 研发的上游,也就是 UI 生产的问题。所以我们希望,在 AIGC 的能力之下,我们的设计协同变成设计和生产一体化的设计协同 ,也就是先 AI2D ,然后 D2C ,设计协同将会从工程化阶段,全面迈向智能化阶段。在后续,我们将继续带来有关AI2D2C 的技术分享。
相关链接
最后
更多岗位,可进入网易招聘官网查看 hr.163.com/