把品牌色写死是一种技术债
每次接手一个旧项目,我都会做同一件事:全局搜索 # 开头的颜色值。
结果通常是这样的:#e44, #e44444, #e44444cc, rgba(228, 68, 68, 0.8)——四个写法,可能指向同一个「主强调色」,也可能各有来历,没人说得清。改品牌色的时候,你得一个个比对,祈祷自己没漏掉某个角落里的裸值。
这是设计系统没有工程化的典型症状。
裸值的问题不是「难改」,是「无意义」
#d97757 这个数字在代码里什么意义都没有。它是橙色?是主按钮色?是错误状态?是装饰性描边?你不知道,读代码的人也不知道。
给它一个名字之后,情况就变了:
--color-accent-orange: #d97757;
--color-accent-blue: #6a9bcc;
--color-accent-green: #788c5d;现在 background: var(--color-accent-orange) 说的是「这里用主强调色」,而不是「这里用这个 16 进制值」。这两句话在语义上是完全不同的。前者传递了设计意图,后者只是实现细节。
这就是 Design Token 的核心思想——用具名引用替代裸值,让代码表达「为什么」而不只是「是什么」。
分层才能真正复用
仅仅把颜色命名是不够的。成熟的设计系统会做两层 token:
第一层:原始值(Primitive Token)
颜色的真实定义,与语义无关:--color-orange-500: #d97757
第二层:语义 token(Semantic Token)
业务含义的映射:--color-action-primary: var(--color-orange-500)
这样做的好处是:换主题时,你只需要改第二层的映射,第一层的颜色库保持不动。比如从橙色主题换成蓝色主题,只需要把 --color-action-primary 指向另一个 primitive,所有用了 --color-action-primary 的地方自动更新。
好的 token 名字回答的是「这个颜色在这里的作用是什么」,而不是「这个颜色看起来是什么」。--color-surface-elevated 比 --color-gray-100 好,因为前者在主题切换时意义稳定,后者在暗色模式下就说不通了。
字体也一样:fallback 不是妥协,是设计
品牌规范里通常会指定一套字体——比如标题用某款几何无衬线,正文用某款人文衬线。但生产环境里字体加载失败、用户系统里没有安装指定字体,是完全正常的事。
工程化的做法是把 fallback 也写进规范:
font-family: 'Poppins', Arial, sans-serif; /* 标题 */
font-family: 'Lora', Georgia, serif; /* 正文 */这不是在将就,而是在声明一条降级路径。Georgia 和 Lora 同属人文衬线,视觉气质接近;Arial 和 Poppins 都是无衬线,切换不突兀。这条降级路径本身是设计决策,应该出现在规范里,而不是交给浏览器随机决定。
工具与代码如何共享这份规范
现在的挑战是:品牌规范往往存在于 Figma、Notion 或一份 PDF 里,代码里是另一套实现,两边各自演化,迟早分叉。
一个务实的做法是把 token 定义作为 single source of truth,从这里生成 CSS 变量、Tailwind 配置、以及给非技术工具(比如 Python 脚本、PPT 处理工具)用的颜色常量。不管哪个工具消费,都从同一份定义取值,改一处,处处一致。
这就是「品牌工程化」的终态——不是一份静态文档,而是一个可以被机器读取、版本管理、自动同步的 token 系统。
一句话心法
裸值是实现细节,具名 token 才是设计意图;让代码说「为什么」,而不只是「是什么」。