探讨 JavaScript Design Tokens 作为统一设计语言的载体,如何在不同平台 (Web, Mobile) 间实现样式和组件的一致性。

咳咳,各位观众老爷,晚上好!我是今天的设计Token特邀讲师,江湖人称“代码界的段子手”。今天咱们不聊源码分析,不谈架构设计,就唠唠嗑,说说这个能让设计师和程序员“相爱相杀”的设计Token。

开场白:设计师和程序员的“爱恨情仇”

话说,在遥远的互联网江湖,住着两拨人,一拨叫设计师,个个身怀绝技,能把界面做得赏心悦目;另一拨叫程序员,个个代码如神,能把设计变成现实。

但是,这俩拨人经常吵架。

设计师:“这个按钮的颜色,我明明说的是#FF4081,你给我搞成#F00是几个意思?”

程序员:“#FF4081和#F00有什么区别?不都是红色吗?”

设计师:“区别大了去了!#FF4081是优雅的少女粉,#F00是奔放的姨妈红!”

程序员:“……(内心OS:这届设计师真难伺候)”

这种“爱恨情仇”的根源就在于,设计师和程序员对“一致性”的理解不一样。设计师觉得是“感觉一致”,程序员觉得是“代码一致”。

而设计Token,就是来解决这个问题的。它就像一个“通用语”,让设计师和程序员都能听懂,从而实现跨平台样式和组件的一致性。

第一章:什么是设计Token?(别被高大上的名字吓跑)

设计Token,英文名Design Token,听起来很高大上,其实就是一堆命名规范的“变量”。 它们代表设计决策的基本属性,例如颜色、字体、间距、阴影等等。这些Token以平台无关的方式定义,然后转换为特定平台的格式。

你可以把它们想象成“乐高积木”,不同的积木有不同的颜色、形状和大小,你可以用它们搭建各种各样的东西。

举个例子,假设你的App有一个主色调,设计师把它定为#007BFF。如果你直接把这个颜色值写在代码里,将来要改颜色,你就得满世界找代码,一个一个地改。

但是,如果你用设计Token,你就可以这样:

// 定义一个设计Token
const primaryColor = "#007BFF";

// 在代码中使用这个Token
button.style.backgroundColor = primaryColor;

将来要改颜色,你只需要改primaryColor的值就可以了,是不是很方便?

第二章:设计Token的优势(好处多到你想不到)

设计Token的好处可不止方便改颜色这么简单,它还有很多其他的优点:

  • 提高一致性: 确保在不同平台和不同组件中使用相同的样式。
  • 方便维护: 修改样式只需要修改Token的值,不需要修改大量的代码。
  • 提高效率: 设计师和程序员可以更高效地沟通和协作。
  • 支持主题切换: 只需要切换Token的值,就可以轻松实现主题切换。
  • 减少错误: 避免手动输入颜色值或字体大小等属性时出错。

第三章:如何定义设计Token?(来点实际的)

定义设计Token需要考虑以下几个方面:

  • 命名规范: Token的命名应该清晰、简洁、易懂。
  • 层级结构: Token应该有合理的层级结构,方便管理。
  • 数据类型: Token应该使用合适的数据类型,例如颜色、数字、字符串等等。
  • 平台支持: Token应该支持不同的平台,例如Web、iOS、Android等等。

一个比较通用的命名规范是:

<category>-<type>-<variant>-<state>
  • category:Token的类别,例如colorspacingfont等等。
  • type:Token的类型,例如primarysecondarybackground等等。
  • variant:Token的变体,例如normalhoveractive等等。
  • state:Token的状态,例如enableddisabled等等。

举个例子:

  • color-primary-background-normal:主色调的背景颜色,正常状态。
  • spacing-small:小间距。
  • font-size-base:基础字体大小。

第四章:设计Token的存储格式(选择困难症患者福音)

设计Token可以存储在不同的格式中,常见的有:

  • JSON: 最常见的格式,简单易懂,易于解析。
  • YAML: 可读性好,适合人工编辑。
  • XML: 比较复杂,但可以支持更高级的功能。
  • CSS Variables: 直接在CSS中使用,方便快捷。

这里我们以JSON为例,举个例子:

{
  "color": {
    "primary": {
      "base": {
        "value": "#007BFF",
        "comment": "主色调"
      },
      "hover": {
        "value": "#0056b3",
        "comment": "主色调,鼠标悬停状态"
      }
    },
    "secondary": {
      "base": {
        "value": "#6C757D",
        "comment": "次要色调"
      }
    }
  },
  "spacing": {
    "small": {
      "value": "8px",
      "comment": "小间距"
    },
    "medium": {
      "value": "16px",
      "comment": "中等间距"
    }
  },
  "font": {
    "size": {
      "base": {
        "value": "16px",
        "comment": "基础字体大小"
      }
    }
  }
}

第五章:如何在不同平台使用设计Token?(重点来了!)

设计Token的核心价值在于跨平台的一致性。那么,如何在不同的平台使用设计Token呢?

答案是:转换!

我们需要将平台无关的Token转换为特定平台的格式。

  • Web: 可以转换为CSS Variables、Sass Variables、Less Variables等等。
  • iOS: 可以转换为Swift Constants、Objective-C Constants等等。
  • Android: 可以转换为XML Resources、Kotlin Constants等等。

下面我们分别以Web和iOS为例,介绍如何使用设计Token。

5.1 Web平台

在Web平台上,我们可以使用CSS Variables来使用设计Token。

首先,我们需要将JSON格式的Token转换为CSS Variables。可以使用一些工具来完成这个转换,例如style-dictionary

style-dictionary是一个非常强大的工具,可以根据Token的定义生成各种格式的样式文件。

安装style-dictionary

npm install -g style-dictionary

创建一个config.json文件,指定Token的来源和输出格式:

{
  "source": [
    "tokens/tokens.json"
  ],
  "platforms": {
    "web": {
      "transformGroup": "css",
      "buildPath": "dist/",
      "files": [
        {
          "destination": "variables.css",
          "format": "css/variables",
          "options": {
            "outputReferences": true
          }
        }
      ]
    }
  }
}

运行style-dictionary

style-dictionary build

这样就会在dist/variables.css文件中生成CSS Variables:

:root {
  --color-primary-base: #007BFF;
  --color-primary-hover: #0056b3;
  --color-secondary-base: #6C757D;
  --spacing-small: 8px;
  --spacing-medium: 16px;
  --font-size-base: 16px;
}

然后在你的CSS文件中使用这些Variables:

button {
  background-color: var(--color-primary-base);
  padding: var(--spacing-medium);
  font-size: var(--font-size-base);
}

button:hover {
  background-color: var(--color-primary-hover);
}

5.2 iOS平台

在iOS平台上,我们可以将JSON格式的Token转换为Swift Constants。

可以使用一些脚本来完成这个转换,例如Python脚本。

下面是一个简单的Python脚本,可以将JSON格式的Token转换为Swift Constants:

import json

def convert_to_swift(json_file, output_file):
  """Converts a JSON file to Swift constants.

  Args:
    json_file: The path to the JSON file.
    output_file: The path to the output Swift file.
  """

  with open(json_file, 'r') as f:
    data = json.load(f)

  with open(output_file, 'w') as f:
    f.write("//n//  DesignTokens.swiftn//nnimport UIKitnnstruct DesignTokens {n")

    for category, category_data in data.items():
      for type, type_data in category_data.items():
        for variant, variant_data in type_data.items():
          name = f"{category}_{type}_{variant}".upper()
          value = variant_data["value"]
          comment = variant_data.get("comment", "")

          # Determine the Swift type based on the value
          if isinstance(value, str) and value.startswith("#"):
            swift_type = "UIColor"
            # Convert hex color to UIColor
            hex_color = value.lstrip("#")
            r = int(hex_color[0:2], 16) / 255.0
            g = int(hex_color[2:4], 16) / 255.0
            b = int(hex_color[4:6], 16) / 255.0
            value = f"UIColor(red: {r}, green: {g}, blue: {b}, alpha: 1.0)"
          elif isinstance(value, str) and value.endswith("px"):
            swift_type = "CGFloat"
            value = value.replace("px", "")
          elif isinstance(value, str):
            swift_type = "String"
            value = f""{value}""
          elif isinstance(value, (int, float)):
            swift_type = "CGFloat" if isinstance(value, float) else "Int"
          else:
            swift_type = "Any"  # Handle other types as needed
            value = str(value)

          f.write(f"    /// {comment}n")
          f.write(f"    static let {name}: {swift_type} = {value}n")

    f.write("}n")

# Example usage
convert_to_swift("tokens/tokens.json", "DesignTokens.swift")

运行这个脚本,就会生成一个DesignTokens.swift文件:

//
//  DesignTokens.swift
//

import UIKit

struct DesignTokens {
    /// 主色调
    static let COLOR_PRIMARY_BASE: UIColor = UIColor(red: 0.0, green: 0.4823529411764706, blue: 1.0, alpha: 1.0)
    /// 主色调,鼠标悬停状态
    static let COLOR_PRIMARY_HOVER: UIColor = UIColor(red: 0.0, green: 0.33725490196078434, blue: 0.7019607843137254, alpha: 1.0)
    /// 次要色调
    static let COLOR_SECONDARY_BASE: UIColor = UIColor(red: 0.4235294117647059, green: 0.4627450980392157, blue: 0.49019607843137253, alpha: 1.0)
    /// 小间距
    static let SPACING_SMALL: CGFloat = 8.0
    /// 中等间距
    static let SPACING_MEDIUM: CGFloat = 16.0
    /// 基础字体大小
    static let FONT_SIZE_BASE: CGFloat = 16.0
}

然后在你的Swift代码中使用这些Constants:

button.backgroundColor = DesignTokens.COLOR_PRIMARY_BASE
button.layer.cornerRadius = DesignTokens.SPACING_MEDIUM
button.titleLabel?.font = UIFont.systemFont(ofSize: DesignTokens.FONT_SIZE_BASE)

第六章:设计Token的管理工具(工欲善其事,必先利其器)

设计Token的管理是一个复杂的过程,需要借助一些工具来提高效率。

常见的管理工具包括:

  • Style Dictionary: 上面已经介绍过了,非常强大,可以根据Token的定义生成各种格式的样式文件。
  • Specify: 一个云端的Token管理平台,可以方便地管理和分发Token。
  • Zeplin: 一个设计协作平台,可以方便地将设计稿中的Token提取出来。
  • Supernova: 也是一个设计协作平台,功能和Zeplin类似。

选择哪个工具取决于你的具体需求和预算。

第七章:设计Token的最佳实践(避免踩坑)

  • 保持Token的语义化: Token的命名应该清晰、简洁、易懂,避免使用过于抽象的命名。
  • 使用合适的层级结构: Token应该有合理的层级结构,方便管理。
  • 避免硬编码: 在代码中尽量不要直接使用颜色值或字体大小等属性,应该使用Token来代替。
  • 保持Token的更新: 当设计发生变化时,及时更新Token的值。
  • 团队协作: 设计师和程序员应该共同维护Token,保持Token的一致性。

第八章:设计Token的未来(无限可能)

设计Token是一个不断发展的领域,未来有无限的可能。

  • 更智能的转换: 自动根据平台特性生成更优化的样式代码。
  • 更强大的管理工具: 更方便地管理和分发Token,支持更多的平台和格式。
  • 与AI的结合: 自动生成Token,根据设计稿智能推荐Token的值。

总结:设计Token,让世界更美好!

设计Token就像一个“翻译器”,让设计师和程序员能够更好地沟通和协作,从而创造出更一致、更易维护、更高效的产品。

虽然它不能完全解决设计师和程序员之间的矛盾,但是它可以让世界变得更美好一点点。

今天的讲座就到这里,感谢大家的收听!希望大家都能掌握设计Token这门“通用语”,让你的团队也能“相亲相爱”!

有问题可以随时提问,或者请我喝杯咖啡,咱们再深入探讨! 谢谢大家!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注