让组件库井井有条

    Collection

    让组件库井井有条 - 图1

    原文引自 medium 上的一篇文章 Keeping Things Organized。该译文并非完整原文,内容已做删减和调整,并加入了部分译者观点。

    如何有条不紊地构建及维护设计组件库?这可不是个简单的问题。面对此问题,向开发同学们学习是个不错的选择。无论是设计元素的命名,还是组件的「封装」,设计同学们都能从程序开发的通用做法中汲取新思路。下面,让我们一起来了解让设计组件库井井有条的方法。

    本期提纲:

    • 原子设计

    • 页面结构化

    • 命名规范化

    • 控件封装

    • Design Tokens

    • 版本管理

    1

    原子设计

    构建组件库,最基本的思维模式即原子设计(Atomic Design)。其实,这个概念并不新鲜,开发同学也有类似的思维模式。

    1.基本概念

    考察代码是否有条理,最好从命名开始。BEM(Block Element Modifier)是一种前端开发所用的模块化命名方法,它能使代码的可读性更高,也更便于协作。BEM 将事物分为 3 个层级来命名:

    Block

    一个有独立意义的实体,对标原子设计中的分子(molecules),如:

    header

    container

    menu

    chackbox

    input

    命名方式为添加一个句号作为前缀,如:.block。

    Element

    Block 的一部分,没有独立意义,对标原子设计中的原子(atoms),如:

    menu item

    list item

    checkbox caption

    header title

    命名方式为在 block 名后添加两个下划线,如:.block__elem。

    Modifier

    用来定义 block 或 element 的样式、表现或状态的元素,如:

    disabled

    highlighted

    checked

    fixed

    size big

    color yellow。

    命名方式为在 block 或 element 后添加两个破折号,如:

    .block—mod

    .block__elem—mod

    .block—color-black

    .block—color-red。

    这里为熟悉前端的设计师举一个实际案例,以了解如何用 BEM 来写下图所示的三个按钮:

    让组件库井井有条 - 图2

    1. HTML
    1. <button class="button">
    2. Normal button
    3. </button>
    4. <button class="button button--state-success">
    5. Success button
    6. </button>
    7. <button class="button button--state-danger">
    8. Danger button
    9. </button>
    1. CSS
    1. .button {
    2. display: inline-block;
    3. border-radius: 3px;
    4. padding: 7px 12px;
    5. border: 1px solid #D5D5D5;
    6. background-image: linear-gradient(#EEE, #DDD);
    7. font: 700 13px/18px Helvetica, arial;
    8. }
    9. .button--state-success {
    10. color: #FFF;
    11. background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
    12. border-color: #4A993E;
    13. }
    14. .button--state-danger {
    15. color: #900;
    16. }

    2.具体实践

    设计同学不需要严格践行开发同学的 BEM 命名方式,但其对页面各元素的分类是值得参考的。

    2

    页面结构化

    结构化页面的基本原则是:

    方便检索控件(Components)

    方便编辑控件

    清晰地传达控件状态

    1.基本概念

    以 React 或 TypeScipt 为例,开发同学会让每个控件都用一个文件夹来将其归纳,如:

    1. src/components/Button/Button.tsx

    让组件库井井有条 - 图3

    1.具体实践

    让每个控件都用一个页面(Page)来将其归纳

    将控件按命名排序

    用 emoji 来表示控件状态

    让组件库井井有条 - 图4

    其中,「🟢」表示控件可用,「🟡」表示控件需谨慎使用,表示「🔴」控件不可用。

    这样做,不仅能方便在页面列表中快速找到所需控件,还能对控件的状态了然于胸。

    3

    命名规范化

    命名的理想效果是,设计稿中的命名与代码中的命名一一对应。虽不能完全做到,但还是需以此为终极目标。关于命名,我们需先了解一些开发同学会用到的命名方式。

    1.基本概念

    部分开发同学会采用 PascalCase(也被称为 UpperCamelCase)这一命名惯例。它要求每个单词的首字母都大写。实际上,类似常用的命名方式还有:

    lowercase

    camelCase

    kebab-case

    snake_case

    但从输入效率和可读性综合考虑下来,PascalCase 对设计师比较友好。

    2.具体实践

    以 PascalCase 为基本命名方法

    用简化后的 BEM 来构建大的命名结构

    下面以 Button 这一控件为例,以示意如何为设计元素命名:

    让组件库井井有条 - 图5

    普通元素

    使用 PascalCase 命名:

    1. [Element]

    如案例中的 IconContainer。

    需进一步描述的元素

    当相同类型的元素同时存在时(如有好几个文字图层),我们可能需要更详细的的描述来帮助我们来区分它们(如有的文字图层用作标题,而有的用作正文)。

    这种情况下,需用破折号连接追加的描述(描述采用 lowercase):

    1. [Element]-[description]

    如案例中的 Vector-min-width。

    使用了自动布局的 frame

    将其中的元素类型进行枚举,用破折号连接,并用「-stack」结尾(只有首个元素用 PascalCase,其他部分均用 lowercase):

    1. [Element]-[element]-[element]-"stack"

    如案例中的 Icons-string-loader-stack,就是一个包含了 icon、string、loader、stack的使用了自动布局的 frame。

    值得注意的是,枚举的元素类型数量不应超过 3。超过 3 个类型时,则按具体情况选择 3 个类型来枚举。

    未使用自动布局的 frame

    用「-container」结尾:

    1. [Description]-"container"

    如案例中的 Loader-container。

    4

    控件封装

    和命名类似,我们希望设计稿中的控件的逻辑结构也能与代码一一对应。由此,我们需要运用以下几个开发同学常用的概念。

    1.基本概念

    API

    API 的全称为 Application Programming Interface。简单来说,API 就像餐厅的菜单。菜单提供了你可以点的菜及其描述。一旦点好菜,餐厅就会为你上这道菜。你不需要了解和参与这道菜的制作过程。

    对于设计师来说,一个控件就相当于一个 API。使用组件库的设计师一般都不需要了解和参与这个控件的制作过程。如下图所示的 Button 控件就相当于一个 API:

    让组件库井井有条 - 图6

    Properties & Values

    对于设计师来说,定义控件的各个变量即为 properties,而变量具体的值则为 values。

    让组件库井井有条 - 图7

    Boolean

    Boolean 是变量的一种类型,包括 true 和 false 这 2 个值。在 Figma 的面板中表现为一个开关(switch)。

    让组件库井井有条 - 图8

    Enum

    Enum 的全称为 enumeration,也是变量的一种类型。它包括了一组被命名的值。在 Figma 的面板中表现为一组聚合在 popup 中的值。

    让组件库井井有条 - 图9

    2.具体实践

    下面两张图分别是 Button 这一控件分别在设计稿、代码中的 prorerties 的表现:

    让组件库井井有条 - 图10

    让组件库井井有条 - 图11

    可以看到,设计稿最终还是没有和代码保持完全一致。但这些不一致都是有意义的,下面我们展开来看。

    变量的合并

    对于设计师,适当合并变量能让控件更易用。

    如:代码中的 primary 和 inverted 两个变量,在设计稿中被合并成了 Appearance 一个变量。

    让组件库井井有条 - 图12

    变量和值的命名

    在代码中,变量命名遵循 camelCase,值命名则遵循 lowercase。而对于设计师, 句首字母大写(Sentence case)可读性更高。

    如:代码中的 iconPosition 变量,在设计稿中被命名为 Icon position;代码中 size 变量及其值 small、medium,在设计稿分别被命名为 Size、Small、Medium。

    让组件库井井有条 - 图13

    控件的拆分

    在代码中,按钮有无图标由 iconOnly 这一布尔(boolean)变量来控制。但因 Figma 的技术及性能限制,设计师最好将代码中的 Button 这一控件,在设计稿中拆分为 Button 和 IconButton 两个控件:

    让组件库井井有条 - 图14

    5

    Design Tokens

    Design tokens 是存储样式值(如色值、字重)的载体。使用它,能简化设计系统的构建和使用,更能推进设计与代码的统一。如下图所示的案例中,FAB 按钮的颜色在设计稿和代码中,均被统一表述为:

    1. md.fab.container.color

    让组件库井井有条 - 图15

    1.基本概念

    Tokens 分为 3 个类型:

    Reference tokens;

    System tokens;

    Component tokens。

    下面,我们以 Material Design(后续均以 md 简述)为例来一一解析。

    Reference Tokens

    这是最基础的一类 tokens。

    其命名以 .ref. 开头,指向一个静态值,如:表示颜色的十六进制代码(#E8DEF8)、字重(Roboto Medium)。

    让组件库井井有条 - 图16

    System Tokens

    这是一种具备「环境感知」能力的 tokens,也被称作 alias tokens。

    其命名以 .sys. 开头,通常指向多个 reference tokens。具体指向哪个 reference token,将由上下文关系(如设备是否为全面屏、是否为深色模式)来决定。

    下图所示的案例中, md.sys.color.background 这一 system token 就会根据系统是否为深色模式来指向不同的 reference tokens:

    让组件库井井有条 - 图17

    Component Tokens

    这是表达组成控件的元素、值(如元素内标题的字体、图标的的各个样式,或控件的具体状态)的 tokens。

    其命名以 .comp. 开头,通常指向 reference token 或 system token

    让组件库井井有条 - 图18

    2. 具体实践

    Design tokens 的概念,能帮助设计师更有条理地理解和整理颜色变量、图层样式、控件等。

    在代码中,tokens 的命名用「.」分隔。但在设计稿中,因软件限制,需用「/」来分隔。

    让组件库井井有条 - 图19

    同时,无论是 Figma 还是 Sketch,样式和控件通常均采用树状结构来进行管理。因此,我们常常会遇到如下图所示的繁琐结构:

    让组件库井井有条 - 图20

    为清晰又方便地枚举样式 ,我们可以用类似于代码的句式来描述。如上图所示的这一组颜色样式就可以通过以下句式来轻松表述:

    1. ["🌕 Light theme" | "🌑 Dark theme"] / ["Rest" | "Hover" | "Pressed" | "Active" | "Focus" | "Disabled"] / ["Foreground" | "Background" | "Border"]

    6

    版本管理

    1.版本号

    对于组件库的版本号,可采用如下格式:

    1. [Major].[Minor].[Patch]

    按此格式,就可以写出类似于「v 1.8.0」的版本号。其中,major 只有全面更新时才会更替,minor 一般指月度版本,patch 则为更小的周版本等。

    2.更新日志

    更重要的是,我们需要在版本更新时向大家清晰传达此次更新的具体内容。因此,我们需在合适的位置维护好组件库的更新日志(Changelog)。而更新日志也可以结构化如下:

    1. Teams Component Library Update: (TCL [date])-[V
    2. 🎉 Whats New
    3. [Component name with link] component
    4. [Component name with link] component
    5. [Component name with link] component
    6. 🛠 Whats Modified
    7. Bug fix for [Component name with link]
    8. Thing updated for [Component name with link]
    9. ⚰️ Whats Moved to Graveyard
    10. Old [Component name with link] component
    11. Old [Component name with link] component
    12. Old [Component name with link] component

    其中,对于弃用的组件或样式,我们可按如下格式对其名称进行标注:

    1. [Current name] / "⚠️ DEPRECATED MIGRATE TO NEW VERSION ⚠️ "

    让组件库井井有条 - 图21

    后记

    诚然,本文提到的很多方法都是比较个性化的,大家在实际的设计工作中可以依据自己所处的团队、所用的应用等因素来进行灵活地调节。毕竟,设计好自己的工作流也是个很重要的设计课题。

    — The end —

    参考文献:

    Josh Cusick. (2020, Oct 22).Keeping Things Organized

    BEM — Block Element Modifier. (n.d.). Get BEM.

    Computer Hope. (2021, February 1). What is a Boolean?

    Facebook Inc. (n.d.). Components and Props –. React — A JavaScript Library for Building User Interfaces.

    Figma. (n.d.). Create dynamic designs with auto layout.

    Google. (n.d.). Material Design 3

    Hoffman, C. (2021, August 13). What Is an API, and How Do Developers Use Them? How-To Geek.

    Tree Hozz. (2020, March 1). What is an enum in Javascript?

    如在阅读过程中发现错误与疏漏之处,欢迎不吝指出。如需转载,请注明来自WeDesign。

    原文链接

    让组件库井井有条 - 图22

    让组件库井井有条 - 图23

    译者:Boren

    小确信之光

    让组件库井井有条 - 图24