介绍
Design Token是在设计中用来存储和管理设计属性的一种方式,几乎所有视图属性都可以建立对应的Design Token,它最大的特点就是可重用性、可维护性、可扩展性、可读性高,设计师和程序员在设计或开发中都可以复用同一套Design Token。
概念是比较抽象的,以下我举一个我们日常中比较经常实用的例子:颜色Token。
Hard code的方式
这里有一块简单的梯度色板,这一块梯度色板是由16进制的颜色的RGB(A)命名。
首先我们可以直观地看到颜色并复制使用其色值,这种方式也称为hard code,这种方式的设计稿和编码的可维护性是极其差的,并且看着这一堆数字也容易摸不着头脑,可读性也非常差。
而在编码中也是如此。
swift
GooseButton(
action: {},
label: { Text("Primary Button").foregroundColor(Color(hex: 0xFFFFFF)) }
).background(Color(hex: 0x9747FF)) // extension function
为叙述方便,文中的代码都使用伪代码的方式实现,未必是最佳实践。
Hard code的问题
一旦使用hard code的方式来使用设计资源将会带来非常多的问题。
可维护性差
如果需要在设计稿或者程序中修改某个类型的属性,将会需要在"使用这个属性"的所有地方进行修改,在代码中尚可使用全局搜索的方式来修改,但是在设计稿中将难以进行这种操作。一旦需要修改,将会在评审阶段产生大量分歧和阻力。
重复度高
如上面所述,在需修改阶段需要对使用了该属性的地方一个个进行修改,这是一项重复度高且无意义的工作,绝大多数情况下,有很多个控价都使用同样的色值,在修改的时候需要一个个核查,这也增加了工作时间,大大降低了效率。
可读性差
由于设计属性都是使用hard code的方式来使用,阅读起来非常的困难,不知道这个颜色指代的是什么。
复用
一般在项目启动阶段,就算设计师没有交付Design Token到程序员那边,程序员也不明白Design Token的概念,程序员也会想到一个问题:复用代码。而如何复用代码呢?
举个例子,在程序开发中新建一个颜色资源时,需要给这个颜色资源命名,这个名字具体是什么?参考什么命名?这些问题一般会抛给设计师,由设计师去定义,而这个起名的过程,也是Design Token初步建立的过程,一旦名字起好了,双方需要严格按照对应名字取使用资源,否则将会产生分歧或设计稿不还原。
一旦建立了名字和颜色的对应,颜色将被赋予语义化,所有控件取什么颜色将有据可依。在设计或开发中将会非常顺畅,大家的协作幸福感将会提高。
协作幸福感是一个非常重要也是最被大家忽视的东西。试想一下,你是一名设计师,你觉得设计稿的某个色值看起来非常不和谐,你把它换成了更舒服和谐的颜色。在评审阶段由于"工作量大,不改也不影响使用"的原因给否决了,你的内心将会非常受挫,而此前所有的调研和工作将白费。换个角度,你是一名程序员,由于历史原因代码中没有复用颜色资源,设计师提出修改某个控件颜色后,你需要花很多时间去做重复的工作,整理设计资源,并且容易产生漏改错改的问题,看到大量的BUG单你会非常头疼。
大家在沟通过程中产生矛盾时将会降低协作幸福感,甚至直接影响工作幸福感、工作效率,这并不利于身心健康发展,容易产生一系列问题。
要规避这个问题,需要提前定义好Design Token并落地,如刚刚所述,Design Token最简单的使用就是将设计资源语义化并复用,如何进一步去更好地使用呢?
设计资源不仅仅指某一个属性,它很广泛,可以是多个属性的集合,例如:字号、粗细、行高的集合,也可以是圆角的参数。
如何构建Design Token
Color Token
以刚刚的梯度色板为例,我们在设计时经常会使用梯度色板来进行配色,各个色阶也可以对应一个命名,如下所示:
具体如何起名,不同的设计系统有不同的起名方式,上图仅供参考。一旦为梯度色板中的颜色起名,该颜色将赋予语义,我们在查找某个颜色的时候可以直接去通过颜色名字搜索,防止产生大量相近但不完全一样的颜色,导致视觉观感上乱七八糟。
而这一层命名未必需要交付给开发,开发没有必要知道你是取哪个梯度的颜色,开发所需要的信息就是这个颜色是什么意思,给谁用的?因此我们需要往下再延伸。
假设我们取刚刚的颜色为品牌主色调,我们为其命名为primary,命名到达这个阶段之后,我们就能很清楚这个颜色是做什么的。
而开发得到这个颜色的命名也足够用于开发了,这也是目前很多项目对于Color Token的用法。
swift
struct GooseColorScheme {
static let primary = Color(UIColor(named: "ref.palette.purple40")!)
}
假设按钮需要使用这个颜色,顶栏也需要使用这个颜色,如果我们需要改按钮的颜色的话,我们需要找到所有按钮,并修改其颜色引用,这非常不友好,我们可以再往下一层。
一旦延伸到component级别,修改某个控件的颜色将变得轻而易举,如果我们需要改悬浮按钮的颜色,直接将component.fab.container的颜色引用修改到目标颜色,不去改变其他控件的颜色即可。这使批量修改控件颜色变得轻而易举。
swift
struct GooseColorScheme {
static let primary = Color(UIColor(named: "ref.palette.purple40")!)
static let primary2 = Color(UIColor(named: "ref.palette.purple60")!)
static let fabColor = primary // 只需修改这个的引用即可
}
// UI
FabButton(
action: {},
containerColor: GooseColorScheme.fabColor,
icon: {},
)
而对于控件而言,不同的状态拥有不同的颜色,例如鼠标悬浮状态,点击状态,禁用状态等等。此时我们还可以往下延伸一层。而具体一个Color Token需要有多少层需要根据实际情况来定,并不是层数越多越好,对于简单的设计系统,过多的层数对于工作效率来说反而起反作用。
Typography Token
文本的参数也可以Token化,以下为Material Design You默认的Typography。
不同语言的字体展示会有所不同,英文的Typography放在中文下可能会有些水土不服,这个可以根据项目的具体情况做调整。
其他设计属性
颜色和字体是最常见建立Design Token的属性,而其他设计属性也可以建立Design Token,如圆角弧度,阴影大小等等,只要你想,所有属性都可以复用。但是并不是Design Token越多越好,有很多属性需要定制,此时它不应该被标准化。
Design Token落地
Design Token是一个约束规范,需要设计和开发达成共识并严格按照其规则来实行,一旦有一方没有落地,Design Token的意义将失去了一半,这也是实际项目中非常常见的误区,我们不能只看到眼前的工作内容,项目的有序进行需要大家互相协同。
- 曾遇到项目的代码为图方便直接以16进制RGBA给颜色命名,而设计有自己的命名规范,这就直接导致在工作中开发跟不上设计进度,设计走查错漏百出。
- 又或者开发以自己的理解给颜色命名了,相似的颜色都复用这个颜色,设计师在后续走查时发现项目里大多数颜色都是错的。
设计师需要及时建立相应的规范文档并交付给开发。这个交付方式多种多样:
- 直接给规范文档开发编写代码来同步,缺点是容易遗漏。
- 可以直接导出类似Json的方式来交付给开发,开发拿到文件再转换成对应的开发资源,可以做到资源同步,并减少遗漏。
如果Design Token通过服务端下发,我们还可以动态下发不同的文件来实现不发版对设计资源热更新。这对于灰度更新、A/B Test或者收集用户意见非常方便。
总结
本文主要介绍了Design Token的概念和用途,Design Token是用于存储和管理设计属性的一种方式,可以实现可重用、可维护、可扩展和可读性高的设计属性。通过使用Design Token,可以实现颜色的复用和语义化,提高设计和开发的协作效率。
在落地过程中设计和开发达成共识是一件非常重要的事情,它不只是某一方的工具,它是推动项目快速迭代,高效维护的关键因素。由于篇幅有限点到为止,而该系列后面的文章主要在于实践,进一步介绍工具的使用和Design Token落地。