前言
Android Q 和 iOS 13 为我们带来了 Dark Mode,这已经不是什么新鲜事了,很多团队都已经拥有了各自适用的解决方案,起点读书的 Dark Mode 设计解决方案也终于从幕后开始进入到项目落地环节,从时间跨度上来讲已经大半年过去了。这段时间经历了各产品解决方案的轰炸与洗礼,我们又结合起点本身的产品定位与结构特点,在此背景下一套融合 Dark Mode 和主题皮肤设计的解决方案应运而生。
本文会重点聚焦设计落地执行的解决方案,视觉解决方案每个产品都有自身不同特点,且 Android 和 iOS 官方都各自拥有符合各自平台的设计解决方案,因此不在此一一赘述。
1.1 概念区分与融合
Dark Mode (深色模式)是在日夜间都可以使用的一种装扮主题,需要满足在日夜间都可以无障碍使用;而夜间模式会比较聚焦于昏暗环境下的阅读体验,是大部分 App 为了用户在昏暗环境下有良好的使用体验专门定制的模式这叫做夜间模式,因此为了不给用户过多的理解负担,我们将这两个概念进行了部分融合。(如下图)
当用户开启 Dark Mode 开关后,非阅读场景不需要用户过于沉浸, 信息的可读性和内容的高对比度可以让信息更加高效的传达,因此为了满足用户不同场景下的使用体验,非阅读场景会使用偏向 iOS 的 Dark Mode 解决方案;而在阅读场景下,为了满足用户的长时间阅读的舒适要求,因此会使用低对比度的夜间模式的解决方案。
在谷歌和 iOS 的官方解决方案中,对主要文字信息表达部分的对比要求大致范围至少 16:1~7:1 之间,而对最低文本的对比度要求是 4.5:1,因此我们基于此参考,最终将两种不同场景的对比度划分为相应可适应区域。
1.2 技术条件决定开发成本
起点本是 Android、iOS、Web 混合的模式,因此设计方案需要能兼顾三端。了解清楚当前产品的结构形态是做 Dark Mode 的前提条件,如组件覆盖率、产品复杂度、技术执行能力等;这几个条件对 Dark Mode 的工作量影响是比较大的,所以在前期最好能评估好这些条件的实际情况。
2. 基本要素
理论上做 Dark Mode 就是做颜色 / 素材映射关系。这个与做主题设计的理论概念是完全一致的,因此我们将两个项目做了合并处理,从设计方案中将 Dark Mode 当成主题来作为解决方案的基础。既然概念不分家,那么在规则制定上会更多的去考虑在主题模式下的设计表现。
2.1 页面层级
整体结构上我们将 App 的页面划分为 4 个层级,背景层、UI 层、悬浮层、弹出层,每个层级还会有自己的子集,我们按照从下至上的顺序来介绍。
背景层对于主题来说背景承载了两种表现形式:纯色、背景图,因此在处理背景颜色映射的时候就需要考虑到该如何支持两种主题的设计关系。
UI 层主要是用于放置所有界面元素、组件的层级。UI 层是颜色分类的基本依据,所以我们如果将 UI 层再进一步划分的话,大致会包含如下内容,背景、文本、元素(图标)、图片、图片上层等。
悬浮层主要包括例如导航栏、工具栏、输入栏、悬浮按钮等都属于悬浮层元素,通常我们定制主题皮肤的时候,都是对悬浮层的元素进行素材改造和氛围渲染。
弹出层顾名思义,就是原本不属于本页面,触发一定条件后在本页面展示的弹出层级,例如我们熟悉的弹窗、半弹层、Action Sheet、Toast 等。弹出层的背景色如何制定在主题皮肤下如何表现,会使用到我们与研发团队共同合作制定的智能取色系统。
通过对层级的划分,我们大致了解了不同层级在适配主题的时候所承载的主要功能,这帮助我们在设计皮肤主题的时候可以快速带入页面、明确色彩关系。
2.2 颜色
颜色我们分三个部分来解析,分别是颜色分类、主题分类、映射方案。
2.2.1 颜色分类
页面层级的划分帮助我们更好的管理颜色,通过此方法我们为每一组颜色打好标签,通过对页面拆解、层级的剥离得到以下比较符合起点业务场景的标签分类,请注意这里的分类不区分色彩倾向,只以功能、页面、层级特点为分类基础。
举个例子,Primary 对应的就是起点的主色红色系,这个标签属于相同色系;而 OnImage 对应的是出现在图片上的颜色,这个标签就属于多个色系颜色;他们各司其职,通过当前的类别划分已经基本上满足起点读书的设计需求,可应对多种场景变化。
但是光看这组标签还不足以帮我们理清思绪,通过判断该颜色是否是影响 App 主题的关键因素,将这些标签分为有映射、无映射、自定义色这三个类别来划分。(如下图)
同为浅色主题(关于主题区分下文会做介绍)的前提下,有映射关系的颜色是指这些颜色在 App 主题中都会有自己固定的色彩映射值,无需我们主动调整,比如 Outline 这个颜色在所有浅色主题中会有自己固定的映射值,不会随着主题的变化而产生改变。
无映射关系是指该颜色不会受主题的影响而产生改变,比如 OnImage 这个颜色就不受主题的影响,它在任意场景下均为相同颜色。
自定义色就是影响主题调性的颜色了,通常我们讲设计主题其实首先就要对这个几个颜色进行调试,前文提到的轻主题就可以通过调整这个分类的颜色就可以快速生成一款主题。
2.2.2 主题分类
刚刚我们提到颜色分类的时候说过在浅色主题前提下,色彩映射可分为三类,那么我们是如何判断深浅主题的呢?深浅主题又该如何做分类?简单一句话概括就是浅色主题就是白底黑字 / 面,深色主题就是黑底白字 / 面;如果我们以 “底(即背景)” 为参照物,那么浅色主题对应的就是用浅色背景的主题,而深色主题对应的就是用深色背景的主题。
我们结合颜色分类和主题分类,就可以总结一个结论,同一个主题分类下的颜色映射除去自定义色以外都是相同的。
那么我们如何区分深浅呢,我们提出了两种解决方案,第一种也是最简单的方法,那就是人为的区分,设计师自己人为的划定主题类别;第二种更偏向于智能化一点,当我们上传了一张 Background 图片或者自定义一个颜色作为背景时,我们可通过对背景取色,取其主色并通过对主色 RGB 值分析来区分所取颜色的深浅,通过深浅自动匹配不同的主题映射方案(如下图)。未来我们将会对两种方案进行整合,纯色背景的主题智能化处理,图片作为背景的主题,依然需要设计师辅助区分。
而刚刚我们所取的主色就可以当做我们的 SheetBackground 来使用,而 Primary 颜色我们可以通过算法匹配出一个相应的主色(算法大意:取背景色的 HSB,色相值 H,然后自定义 S、B 的数值就可以匹配出我们需要的颜色)或者自定义一个主色亦可。
2.2.3 映射方案
在具体落实方案上还有很多细节点,比如我们在 Background 颜色 / 背景上通常会覆盖一层黑色半透明,主要是因为特定情况下该颜色会与 SheetBackground 产生交集。
在日常的 UI 设计中往往还会遇到 Design Token 颜色不够用,还常常用到其他颜色的情况,虽然是小概率事件,但我们依然需要将其纳入到设计流程中,为避免双方(设计与研发)使用直接的 RGB 色值,我们又制定了一套色码表,色码表收录了包含 Design Token 的所有颜色,并且有规律可循,这样我们就可以保证与研发的双向约束。以下为起点的 Design Token 命名映射表单以及色码表一览。
关于同色不同标签,也同样拥有很多注意点,比如白色 #FFFFFF 这个颜色,在 Background、SheetBackground、NavBarBackground、Surface、OnImage 中都有出现,但是各自的颜色映射关系都有点不太一样,在 Background 中需要映射背景或者自定义颜色,在 SheetBackground 中需要依托取色或者自定义,在 NavBarBackground 中又是全透明的映射关系,而在 Surface 是一套固定的映射关系,出现在 OnImage 却又不需要映射。
2.3 素材的适配方案
将端内的素材按照类型分大致可分为五类:单色图标、多色图标、缺省图、氛围图片 / 动画文件、书封 / UGC 图片。对于不同的素材需要有不同的处理方案。
单色图标因为使用的是 Svg,所以只需要进行着色处理即可。
多色图标以金刚区为例,通常产品金刚区的图标来源于本地素材和服务端下发这两种场景,如果是本地素材,可以内置两套素材;而服务端下发的图片素材,在无法基于 Dark Mode 自动替换的前提下,只能使用一套基础图片。然而客户端对服务端下发的图片的可编辑性是非常有限的,目前仅能对单色图片做着色处理;众所周知金刚区的图标风格都比较强烈且偏个性表达,因此如何解决不同皮肤下的金刚区图标风格问题,我们尝试了一下有效解决方案:
结构拆分法,以下图为例,将原图标拆分为上下两层结构,不同主题下客户端仅需对图标底部背景色进行 Token 绑定即可。这种解决方案的下的产品主题皮肤更加沉浸、风格更加统一。
一套图解决思路,将原本设计调整为可适应多场景的风格;这样的解决方案好处在于给了设计师更多的发挥空间,可以在金刚区尝试不同的设计风格,同时还可以拓展动态图标的运用,这些自定义操作都不会受限于客户端的展示形式。
缺省图提供双风格的样式即可,或者调整风格为多场景通用的样式。
氛围图片 / 动画文件通常是装饰作用的素材,因此大部分不需要进行映射处理。
书封 / UGC 图片遵照应对多场景使用均可使用的原则,因此不对图片做过透明度 / 遮罩 / 对比度等处理。
3.1 如何保证设计准确性
我们在构建组件库时需严格按照颜色的使用标准和标签来用色,做到所有颜色均从 Design Token 中调用;日常版本迭代中设计师也需要遵守用色标准,无需映射的颜色或者特殊用色也可以从色码表中获取。当然只要是人为进行的操作就肯定会有出错的情况,为此我们又借助 Figma 中的 Themer 插件可以做到颜色一键切换的效果,可以帮助我们快速检索用色错误的元素。
3.2 研发接入方式
Android、iOS、Web 接入的前提条件是已经拥有比较高的组件覆盖率;通过与研发同学的通力合作,我们搭建各端的 Design Token,这其中包含颜色、字体、阴影等视觉属性。通过 SDK 的方式管理 Design Token,确定好哪些映射关系可以统一替换,哪些是需要自定义下发的。
以安卓为例,初始化的时候有 3 套基本 Token 的映射,分别是 Dark Mode、深色皮肤、浅色皮肤。当切换主题后会判断主题类型并为之匹配不同的映射方案,随后会跟随皮肤主题色来改变部分影响皮肤调性的 Token 映射。因为深色皮肤和浅色皮肤模式下部分颜色来自取色或自定义下发的 Token 文件,所以在 Dark Mode 模式下需用借用技术手段 Hook 住此类颜色,从 Apk 的资源管理器中取得我们预制好的 Token 即可。
这样的接入方式,无需对整个 App 进行页面一对一的适配调整,对设计师来说要求更加的严格了,需要更加工程化的思维来设计页面,但是降低了我们的沟通成本。Design Token 同时还让 App 兼具了换肤的功能,对于做设计赋值都是比较好的方式;对于研发同学来说这将大大的降低了接入 Dark Mode 所带来的繁重工作量(对复杂产品来说,工作量确实比较繁重),同时在保证设计还原上面也能得到比较显著的提升。
4. 客户端与系统的解耦方式
Dark Mode 目前在 iOS13 + 系统以及少部分安卓手机才拥有相应的系统开关,基于安卓复杂的生态系统,我们对安卓暂时采取了比较一刀切的设计方案,暂时不跟随系统;iOS 则以 13 作为比较明确的界限,iOS13 以下用户和安卓用户在客户端内操作即可实现两种模式的切换(如下图)。
而在 iOS13 + 系统中,因为同时存在系统开关、端内开关两种模式;而端内开关不仅仅只有深色模式,还需保留相应的皮肤拓展能力,因此不能一刀切的直接与系统开关做绑定关系;此时则需要另外增设一个是否跟随系统的开关。那么当三个开关摆在我们面前,复杂三角关系就形成了。基于此 if 的情况比较复杂,具体处理方式可查看下图。
当起点需要做 Dark Mode 时,我们已经明白这对设计团队和研发团队都是一场考验,而这其中最难的并非是设计方案的制定,方案的推进与执行才是最大的考验。项目初期我们通过对双端规则的研究,结合起点产品的现状,制定了这一套 Design Token 解决方案,这套方案对于成熟的团队可能作用甚微,但对于还纠结于此事的团队来说,应该可以提供一些帮助,对于文中提到的观点欢迎留言参与讨论。
感谢每一位为此项目付出的设计、研发、测试、服务端等小伙伴。
可通过以下二维码下载起点读书 App,Dark Mode 已上线,欢迎指正👇
本文作者:杨雪松
转载请向阅文体验设计微信公众号 ( id: YUX_design ) 获取授权,并注明作者、出处和链接
其他设计干货
文章不错,点个在看吧!