JSON设计令牌需扁平化为--color-primary等CSS变量名,数值字段补单位(如px),颜色保持原样,布尔值不转变量;通过动态style标签注入:root,避免覆盖与冲突。

JSON 设计令牌里字段名怎么映射成 CSS 变量名
直接把 JSON 键名当 CSS 变量名会出问题,比如 primary-color 这种带连字符的键,在 CSS 里不能直接当变量名用(--primary-color 是合法的,但 JSON 解析后作为 JS 对象属性时,obj.primary-color 会报错)。更常见的是嵌套结构,像 {"color": {"primary": "#007bff"}},得扁平化成 --color-primary 才能被 :root 使用。
推荐做法是递归遍历 JSON,用 Object.entries() + join('-') 拼路径。注意跳过非基础类型(函数、null、undefined),只处理 string/number/boolean:
function flattenTokens(obj, prefix = '') {
const result = {};
for (const [key, value] of Object.entries(obj)) {
const fullKey = prefix ? `${prefix}-${key}` : key;
if (value && typeof value === 'object' && !Array.isArray(value)) {
Object.assign(result, flattenTokens(value, fullKey));
} else {
result[fullKey] = value;
}
}
return result;
}
生成 :root CSS 变量时要不要加单位或转换值
JSON 里存的 "spacing-sm": 4 是纯数字,但 CSS 中 --spacing-sm: 4 不合法,必须补单位(如 px 或 rem)。同样,"opacity-disabled": 0.3 可以直接用,但 "z-index-modal": "999" 字符串得转成 number 避免运行时计算失败。
- 数值类字段(spacing、font-size、border-width)默认加
px,除非显式标记单位(如"font-size-h1": "1.5rem") - 颜色字段(color、background)保持原样,CSS 原生支持十六进制、rgb()、var() 等写法
- 布尔值(is-dark-mode)不转 CSS 变量,这类更适合生成 class 切换逻辑,而非 CSS 变量
如何把 JS 对象注入到 :root 而不覆盖已有变量
直接 document.documentElement.style.setProperty('--x', val) 效率低且难维护。更稳的方式是动态创建 <style> 标签,一次性注入全部变量,并加注释方便调试:
立即学习“前端免费学习笔记(深入)”;
const cssVars = flattenTokens(yourJsonTokens);
const cssText = `:root {\n ${Object.entries(cssVars)
.map(([k, v]) => ` --${k}: ${typeof v === 'number' ? v + 'px' : v};`)
.join('\n')}\n}`;
const style = document.createElement('style');
style.textContent = cssText;
document.head.appendChild(style);
注意:如果项目已用 CSS-in-JS 或构建时处理变量(如 PostCSS),别在运行时重复注入,否则可能冲突。检查 getComputedStyle(document.documentElement).getPropertyValue('--color-primary') 是否已存在再决定是否写入。
为什么用 CSS 变量而不是直接生成 CSS 类
CSS 变量适合主题切换、运行时修改(比如暗色模式 toggle)、配合 calc() 动态计算;而生成固定类名(如 .bg-primary)更适合构建时确定、无需 JS 干预的场景。两者不是替代关系,但混用容易出问题:
- 不要让同一个设计值既出现在
--color-primary又出现在.text-primary的color声明里,维护成本翻倍 - 避免在 SCSS 中用
@each循环生成变量——那本质是编译时静态输出,和 JSON 令牌的运行时灵活性冲突 - 若需 SSR 支持,JSON 令牌必须在服务端也可用,不能只靠客户端 JS 注入
真正麻烦的不是转换逻辑本身,而是设计系统里「哪些值该进变量、哪些该进类、哪些该进主题配置对象」的边界划分——这个得团队对齐,光写脚本解决不了。


















