作者:彧瑾
以下全文是笔者根据在 GMTC 大会 上的演讲稿整理而来,特为没能去现场的朋友们献上~
大家下午好,今天我要和大家分享的主题是《网易云音乐基于 C2D2C 的「无损」设计协同》。
按照惯例,在开始之前,我先作一个简单的自我介绍:
我今天分享的大纲分为 4 个部分,分别是:
- 背景和问题
- 基于 C2D2C 无损设计协同的介绍
- 方案设计与技术挑战
- 总结与展望
背景和问题
什么是(大前端)设计协同
在开始之前,我们先明确一个概念:就是什么是(大前端)设计协同?
我的理解,所谓(大前端)设计协同,简单来讲,就是在设计师和开发的合作下,将产品需求转化成代码的过程。
然而,在实际的设计协同中,往往存在一些令人头疼的问题。
设计协同中存在的问题
拿云音乐来说,首先,设计资产是通过人肉管理的,设计规范也是人肉同步,而且不同的设计团队之间设计标准不一,设计资产存在重复建设。
而开发作为设计的下游,则会连锁受到影响。具体体现在:
- 对于同一个组件,因为规范的不同导致重复开发;
- 像换肤这样的三端联动场景,开发也不得不重复实现三套。
- 最后,由于开发侧需要人肉还原设计稿,效率较低,容易造成开发资源瓶颈。
此外,设计和研发除了在各自领域内存在问题外,彼此间的串联也存在问题。具体为:
- 在开发前,由于设计和开发彼此间存在 GAP,在一些边界问题和能力范畴等问题上会反复对焦,沟通成本大;
- 在开发过程中,开发需与设计就细节频繁沟通,工作效率低;
- 开发完成后,因为开发人员长期处在 时间紧任务重 的「赶工式」状态,导致最后的视觉还原度低,设计验收效率低
如果我们对以上问题进行分类和总结,就会发现,设计协同中的问题基本可分为「沟通问题」和「效率问题」,而且彼此间互有重叠,相互交错。
比如设计资产的人肉管理,既会导致「沟通问题」也会导致「效率问题」。
传统的解决之道
为了解决上述问题,业界传统的做法一般是采取以 设计系统 为中心的「有损」设计协同。
具体做法是提供 两套 组件库,一套是给设计用的 Sketch 或 Figma 组件库,一套是给开发用的 React 或 Vue 组件库。
确实,通过设计系统能在一定程度上解决「沟通」和「效率」的问题。但是这种做法会在无形中造成设计意图传递的损耗,为什么这么说呢?
这是因为,在以设计系统为中心的解决方案之中,设计规范存在两套相互独立的实现,分别对应为设计资产和组件代码,而且彼此不同源。
这就导致了设计意图从设计师传递到开发者存在比较多的「信息损耗」,而这种「损耗」必须通过 人的沟通 才能解决,引入了不确定性和时间成本
「有损」设计协同之殇
现在,我们总结一下:「有损」设计协同来的问题主要有三个。
- 首先,维护成本较高。因为我们需要同时维护设计和开发 2 套组件库;
- 其次,协作效率低。因为信息损耗的存在,所以,设计和开发需要通过反复沟通来消除不确定性;
- 最后,局部的效率比较低。具体表现在,设计师在做稿时,仍然需要较为频繁的手改文案,调整布局;而开发在还原 UI 时,则需要手撸代码,人肉去还原。
我们知道,彻底解决一个问题关键,在于找到其症结所在。
症结在哪里
造成「有损」设计协同出现问题的本质原因,就是因为设计和开发的工具体系缺少统一的协作语言。
设计师使用的是设计语言,而开发者使用的是开发语言,彼此不同源,设计意图的传递不可避免存在损耗。
设计协同新思路
所以,为了彻底解决此问题,最好的做法就是从工具侧打通设计和开发,统一协作语言。
为此,我们基于此思路,提出了 基于 C2D2C 的无损设计协同
基于 C2D2C 无损设计协同的介绍
C2D、D2C 简介
首先,和大家简单介绍一下什么是 C2D 和 D2C。
所谓 C2D,全称是 Code2Design,也就是将代码转成设计稿。
而 D2C,则是其逆过程,将设计稿转成代码。
「无损」设计协同的核心
而无损设计协同的核心,就是借助 C2D 和 D2C,用代码及其衍生物统一协作语言。
具体而言,设计师借助 C2D,将设计意图表达成设计语言,这里的设计语言不仅包含图层数据,还包含图层所对应组件的元数据信息,包括组件名,组件的配置参数。
然后开发者借助 D2C,通过消费图层和组件元数据,将设计语言表达成开发语言。
因为在组件元数据中包含了完整的设计意图,所以从理论上讲,这就实现了设计意图的无损传递。
「无损」设计协同的优势
与有损设计协同相比,无损设计协同的优势体现在 3 个方面:
- 首先,是维护成本低。因为只需在开发侧维护一套组件库即可。
- 其次,是协作效率比较高。因为设计细节无损保存在元数据中,免去了反复确认。
- 最后,是局部效率比较高。因为设计师可以利用 C2D 快速生成设计稿,开发者利用 D2C 快速还原 UI。
方案设计与技术挑战
那要怎么实现基于 C2D2C 的无损设计协同呢?接下来,将会和大家详细介绍我们的方案设计与技术实现。
产品全景图
现在,呈现在大家面前的,是云音乐 C2D2C 的产品全景图。
最下面是设计规范,基于设计规范我们构建出了整套组件体系,覆盖 H5、RN、iOS、Android 四个平台,在实现上,通过共享 Design Token 保证了 UI 的一致性。
而所谓 Design Token,可以将其理解成一种将组件样式与代码解耦的实践:先将用于控制组件样式的颜色、字号、圆角、边距等设计要素抽离成变量(也就是 Design Token),然后在实现上,通过引用 Design Token 来实现组件样式,这样不仅可保证三端组件 UI 的一致性,还能很容易地实现诸如动态换肤、品牌风格改版等「高级功能」。
基于组件体系,我们构建了 C2D2C 的工具体系,包括 C2D 和 D2C 两大关键能力,以及基于此的 Sketch 和 Figma 插件。
最后,我们将 D2C 的出码与低代码平台进行打通,最终形成了 C2D2C 协同流程的闭环。
核心流程
整体 C2D2C 的协同流程可以简化成下面这张图:
首先,业务设计师利用 C2D 插件搭建出业务设计稿,然后交付给 业务大前端开发。
业务大前端开发拿到设计稿后,利用 D2C 插件,便可以产出目标代码。
然后 D2C 插件便将代码推送到低代码平台,进行二次开发和调整,完成之后,便可以通过发布平台进行发布上线了。
C2D2C 功能演示
这里有一个一分多钟的演示视频,大家可以跟随着我,一起来感受一下:
https://crazynote.v.netease.c...
首先,我们的设计师打开 figma 的 C2D 插件,从插件的组件面板中拖拽出一个 Tab 组件,拖拽完成后,可以选中组件并唤起配置面板进行相关的配置。
随后,我们按照相同的做法,拖拽出一个底部导航栏、一个大图卡片、一个图文卡片和一个文字卡片。
页面搭建完成后,我们便可以打开 figma 的 D2C 插件,D2C 插件有一些配置项,可以分别配置 D2C 的目标平台,页面布局等参数。
然后我们将此页面与低代码应用进行,最后点击生成,代码就会被推送到远端 gitlab 仓库。此时,我们点击在线开发,便可跳转到低代码平台,进行二次开发。
我们可以通过搭建的方式进行二次调整,也可以直接通过源码进行二次开发,且二者之间是可以互转的。
经过刚才的演示,相信大家对 C2D2C 已经有了一个整体上的理解。接下来,我将会就一些比较关键的点,展开讲讲我们是如何实践的。
跨平台的插件架构
因为我们的设计插件覆盖了 Sketch 和 Figma 两个平台,为了降低开发成本,我们设计了跨平台的插件架构。
跨平台的核心思路其实比较简单,就是用 Web 来承载 UI 和业务逻辑。
我们可以把插件分成 端容器 和 Webview,容器负责渲染和通信,Webview 负责 UI 和业务逻辑。
但是这样做会存在一些挑战:
首先, Sketch 和 Figma 插件视觉交互不一致。这主要是由插件 API 能力的限制以及配色差异导致的。
其次,Sketch 和 Figma 插件容器与 Webview 的通信方式不统一,图层的渲染逻辑也存在差异。
所以,如何才能用一套架构 Cover Sketch 和 Figma 两个平台呢?
为此,我们对插件的架构进行了分层设计,分为底层的运行时、作为容器的渲染层、负责通信的协议层、业务逻辑层,以及负责 UI 展示的视图层。
通过这样的合理分层,Sketch 和 Figma 便可以完全复用业务逻辑代码,同时也能根据平台的不同,进行单独的适配。
设计稿配置化方案
回到插件本身,在前面的部分我也提到过,我们希望插件能够帮助设计师提效,从繁琐的文案和布局的调整中解放出来。
为此,我们实现了基于 C2D 的设计稿配置化方案:
配置化的核心是动态表单 + 元数据绑定。从设计师视角来看,配置行为可以分为「首次配置」和「二次配置」
首次配置时,用户直接从插件中将所需要的组件拖拽出来,通过 C2D,将目标组件转成图层信息,同时将组件的配置信息,也就是组件元数据绑定到图层上。
二次配置时,当用户点击图层时,会触发插件从图层读取组件元数据,并利用动态表单渲染出配置面板,这样用户便可以实现二次的配置
所以,设计稿配置化的核心,就在于如何去做 C2D。
C2D 技术选型
我们知道,C2D 的本质是代码转成设计稿,在业界,目前做 C2D 一般有两种思路:
一种是将 Sketch 或 Figma 作为 React 的一个端,利用类 RN 的语法,渲染出设计稿,比如 airbnb 的 react-sketchapp;
另一种思路,则是直接将组件的 html 转设计稿,比如 ant-design 的 html2sketch。
第一种方案要求我们针对 Sketch 或 Figma 适配一套组件库,比较优雅,但是成本较高,也会带来后续维护的问题。
第二种基于 html 的方案则与具体的技术栈无关,通用性强。
在综合考虑成本和收益后,我们最后选择了第二种方案。
对 Sketch 而言,由于其发布的时间早,C2D 的生态相对成熟,基于 html 的开源方案有 html-sketchapp、html2sketch,但是 html2sketch 作为后来者在还原度上更佳,所以我们选择 html2sketch 作为 Sketch 的 C2D 方案。
而 Figma 由于是 2016 年发布的,相对年轻,其 C2D 的生态还不够成熟,基于 html 的开源方案有 figma-html,但是其还原度做的还不够好,所以我们参考了 figma-html 的思路,选择了自研 html2figma。
html2figma 实现原理
html2figma 的本质,其实就是 DSL 的转换,将描述网页 UI 的 html,转换成描述 Figma 设计稿的 Schema。
具体而言,就是将 html 的元素,比如 div 标签、p 标签、svg 标签,映射成 figma 的 frame 节点、文字节点和矢量节点。
对于除 svg 外的常规节点而言,转换的过程就是将元素 CSS 的属性映射成 节点的属性。
不管是 html 还是 figma 的 Schema,由于二者在描述 UI 上都具备完备性,所以这种属性的映射从理论上讲,是完全没有问题的。
我们可以举一个例子进行说明:
比如,我们有一个 div 元素,通过 CSS,让它成为了一个直径为 80px,颜色为红色的圆。
我们则可以将其转换成 Figma 的 Frame,长和宽分别为 80px,填充色为红色,圆角为 40px。
可以看到,转换之后,二者在视觉上完全一样。
但是 SVG 比较特殊,SVG 的解析比较复杂, SVG 本身可以看成一门独立的 DSL。Figma 官方可能也是考虑到这点,为了保证 SVG 渲染的一致性,提供了直接将 SVG 字符串 转换成矢量图形的 API。
所以针对 SVG 的转换就变的异常简单了,不用解析,直接原封不动传给 figma 即可。
举个例子,比如,这里有一个音符的图标,我们直接获取其 svg 源码,然后转交给 figma 进行渲染,转换之后,二者在视觉上完全一样。so easy!
刚才和大家讲完了 C2D 是如何实现的,那 D2C 又是如何实现的呢?
D2C 方案设计
D2C 的本质
说到 D2C,大家首先想到的可能就是阿里巴巴的 imgcook,或者是京东的 Deco,特别是 imgcook,大家耳熟能详的原因,是因为它率先实现了将 AI 应用在 D2C 上,而且取得了不错的效果。
这可能就会造成一种误解,认为 D2C 就一定要用到 AI,其实不是的。
因为 D2C 的本质是将设计意图还原成代码,所以 D2C 的关键就在于如何让机器理解设计意图。
对于一张图片而言,因为它是非结构化,它所包含的信息完全蕴含在其二维像素平面内,对于这种场景,用 AI 去做 D2C 是非常合适的,但是成本会比价高,因为会涉及到大量的标记和模型的训练工作。
如果是对于 Sketch 或 Figma 的设计稿而言,因为其本身是结构化的,所以将其转换成代码是完全可行的,社区的很多插件都可以做到这点。
但是,真正的难点在于物料识别,也就是如何识别图层,将其与组件库进行关联。
基于元数据的 D2C
相信讲到这里,细心的朋友已经能明白,之前在做 C2D 的时候,为什么要在图层中绑定元数据了呢?其实就是用来做物料识别的。
所以,我们的 D2C 方案,就是基于 元数据 的 D2C:
原理并不复杂,基于 C2D 的产出的设计稿,我们会解析设计图层和元数据,同时进行物料的识别,最后还原成代码。
比如,对于 Button 而言,C2D 在生成设计稿时,会为图层绑定组件的元数据,包括组件名、组件 Props,API 文档等,D2C 时,直接读取组件元数据,翻译成代码即可,其间不会丢失任何的设计细节。
没有元数据怎么办?
但是,对于云音乐而言,除了标准化的产品功能页面外,还有一类页面场景,它们就是云音乐特色的活动页面,其创意性强,难于标准化。
相信大家在朋友圈或多或少见过他们的身影,比如恋爱人格测试活动,摸鱼计算器活动,以及大家喜闻乐见的年度报告。
那对于这类缺少元数据的设计稿要如何处理呢?
我们的做法也相当直接:既然你没有元数据,那我就人为补上元数据。
我们通过约定,在设计稿的结构、作图和命名上进行规范。
对于设计稿的结构,我们会将其规范为页面、组件和素材三部分,每部分承载各自的功能,彼此间不交叉。
对于作图规范,则要求设计师具备组件化的思维,将复用的 UI 抽象成组件或组件变体,并通过变体的参数进行区分。这样的做的理由是让最后产出的代码的可读性和质量更高。
最后是命名规范,也比较简单:就三条:
- 如果是完整页面,则名称前添加 # 前缀进行标识;
- 组件名要遵循语义化原则,不能使用特殊符号,这主要是为了方便生成组件名代码
- 如果某个区块想做为切图展示,则直接利用 Fimga 进行标记即可。
做完以上工作后,设计稿的元数据就算添加完成了,可以执行 D2C 了:
PPT 右侧就是刚才摸鱼活动的设计稿 D2C 生成的代码:可以看到,生成的代码有组件的划分、有合理的布局结构,具备较强的可读性和二次开发的能力。
大家可能会好奇,这么漂亮的代码是如何生成的?接下来,我将会和大家一起来揭秘。
D2C 核心流程
下面这张图是 D2C 的核心流程图,总体流程分为 4 步:
首先,拿到设计稿后,会经过图层预处理进行图层精简。
紧接着,执行 UI2Schema,生成与平台无关的中间产物,期间,会有一个可选流程,做布局的优化,主要功能是将绝对定为布局转为相对定位。
然后,执行 Schema2Code,生成目标代码。
最后,进行二次开发和标准最后是上线。
我们先看第一步,图层预处理。
图层预处理的主要目的是精简图层,降低 D2C 的复杂度。
因为对于一个图层而言,如果包含元数据,则证明它能够被识别成一个已知的组件,其子图层已没有太多价值,可以被完全被移除掉。
所以,图层预处理,能在很大程度上降低图层解析的复杂度。
图层精简完后,就到了第二步 —— UI2Schema 。
UI2Schema 主要目的是将设计稿转成与平台无关的中间产物,这里的平台既包括 Sketch/Figma 这样的设计平台,也包括 React、RN 这样的代码平台。
那为什么要这么做呢?是因为我们的面临的场景比较复杂。
在设计侧 ,Sketch 和 Figma 都在使用,端侧,React、RN、 iOS、Android 都需要支持。
所以,通过中间层抽象之后,就可以实现跨设计平台和跨端。
刚才也提到,UI2Scehma 中有一个可选流程的,那就是布局优化。虽然是可选流程,但是对于最终生成代码的可读性而言,却是颇为关键的。
我们可以举个例子进行说明。
PPT 左侧有一个设计稿,包含 ABCD 四个节点,如果不进行布局优化,那么整个页面将是一个扁平的结构,生成的是绝对定为的代码。虽然还原度能够保证,但是可读性比较差。
而布局优化的过程,则是对 ABCD 进行分组,首先将页面分为 ABC 和 D 两行,然后将 ABC 分为 A 和 BC 两列,最后将 BC 分为 B 和 C 两行。
分好组后,通过新增三个布局容器,形成行列嵌套结构,这样最终生成的代码将符合开发者的直觉,具备较好的可读性。
不难发现,做布局优化,其实就是在做行列分割,那具体要如何实现呢?
整个流程,其实可以分为 5 步。
首先,我们需要获取到待处理的节点坐标
然后,进行节点关系的处理:判断它们是处于包含、还是相交还是相离关系:
- 如何是包含关系,则将被包含的节点作为其子节点处理;
- 如何是相交关系,则将两者看做一个整体,且其中一个相对于整体作绝对定位处理;
- 如果是相离,则不做额外处理。
节点关系处理完成后,则是做二维空间投影,找到行列分割的依据。
比如,通过纵向投影,我们就知道了 ABC 和 D 是属于不同的两行;通过横向投影,我们就知道了 A 和 BC 属于不同的两列。
接下就是做行列分割了,其主要工作就是依据二维投影信息,添加布局节点,进行分组。
最后就是样式的计算,生成包括 Flex 布局、绝对定位以及 Margin 偏移量的样式信息。
Schema 生成后,下一步便是 做 Schema2Code,也就是多端代码的生成。
值得注意的是,为了能够支持生成多端代码,我们在 Schema 中标注的组件其实是虚拟组件,在转换成代码时,会查询维护的一份组件映射表,最后将其转换成真实的组件。
代码生成后,便可以进行本地或在线开发。在线开发同时支持可视化搭建和源码开发,并且二者之间可以相互转换。
对于 iOS 和 Android 而言,因为技术上的限制,目前暂仅支持本地开发。
C2D2C 的技术细节就先聊到这里,接下来,将会做一个简单的总结与展望。
总结与展望
目前基于 C2D2C 的工作流已经打通,协同流程已经闭环,现已在云音乐 4 大场景进行了落地,包括活动、商城、会员和音乐人。
平均能为设计师提效 25%,研发提效 33%,协同整体提效 38%。
当然,C2D2C 未来在云音乐还有很长的路要走。
首先,C2D2C 的能力需要持续的完善,并建设相应的规范和标准,作为底层能力进行下沉,赋能兄弟团队,帮助解锁更多的平台侧玩法,比如为 H5/RN 搭建平台 和 Native 动态下发平台提供出码服务。
此外,C2D2C 还需要接入除基础组件之外的更多物料,协同各业务组一同建设物料生态,使整个物料生态越来越繁荣。
最后,在 C2D2C 核心能力、物料生态和平台侧玩法三驾马车的共同作用之下,无损设计协同将形成一个增强回路,共同放大 C2D2C 的价值。
最后,打个小广告~
我们将会在 今年 Q1 开源 C2D2C 的基石,也就是云音乐自研的海豚 RN 组件库。
它是一个高质量的 RN 组件库,基于 TS 和 Hooks 实现,具备强大的主题配置能力。
它包含 50 多个组件,经过了内部 100 多个项目的验证,大家可以期待一下!
最后,感谢大家的时间,谢谢!
本文发布自网易云音乐技术团队,文章未经授权禁止任何形式的转载。我们常年招收各类技术岗位,如果你准备换工作,又恰好喜欢云音乐,那就加入我们 grp.music-fe (at) corp.netease.com!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。