关于 style-dictionary
style-dictionary 是一项设计令牌配置技能,指导将单一来源的令牌转换为面向不同平台的代码格式。它涵盖自定义转换与输出格式、多主题配置及构建流程集成。
主要功能
- 01从令牌源生成平台专属输出
- 02转换颜色、尺寸等令牌值
- 03配置自定义转换与输出格式
- 04设置多主题和多品牌令牌
- 05集成令牌构建流程
适用场景
- 01为 Web、iOS 和 Android 输出设计令牌
- 02将 Figma 导出的令牌转换为代码
- 03在构建流程中自动生成令牌文件
- 04扩展令牌转换或输出格式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dylantarre/ design-system-skills --skill style-dictionary安装后在 Claude Code 中输入/style-dictionary确认已加载。
详细介绍
Style Dictionary
概述
设置 Style Dictionary,将设计令牌转换为特定平台的格式。这是设计系统领域的行业标准,可从单一令牌源生成适用于 Web、iOS、Android 及其他平台的内容。
适用场景
- 为需要支持多个平台的新设计系统进行设置
- 将 Figma 令牌转换为代码
- 从同一来源生成 CSS、SCSS、iOS Swift、Android XML
- 添加自定义令牌转换或格式
- 将令牌集成到构建流水线中
快速参考:核心概念
| 概念 | 用途 | 示例 |
|---|---|---|
| 令牌 | 带有元数据的设计值 | { "value": "#3b82f6", "type": "color" } |
| 转换 | 转换令牌值 | color/hex → color/rgb |
| 格式 | 输出到文件类型 | CSS 变量、Swift、XML |
| 平台 | 目标环境 | web、ios、android |
流程
- 评估令牌来源:令牌定义在哪里?(Figma、JSON、YAML)
- 确定平台:哪些平台需要令牌?
- 设置配置:创建
style-dictionary.config.js - 定义转换:添加任何自定义值转换
- 构建:运行
style-dictionary build
实施清单
设置 Style Dictionary 时复制此清单:
Style Dictionary Setup:
- [ ] Install: `npm install style-dictionary`
- [ ] Create tokens/ directory with source JSON files
- [ ] Create style-dictionary.config.js with source paths and platform outputs
- [ ] Add build script to package.json: `"tokens:build": "style-dictionary build"`
- [ ] Run build and verify output files are generated correctly
项目设置
安装
npm install style-dictionary
# or
yarn add style-dictionary
目录结构
tokens/
├── base/
│ ├── colors.json
│ ├── spacing.json
│ └── typography.json
├── semantic/
│ ├── colors.json
│ └── components.json
└── themes/
├── light.json
└── dark.json
build/ # Generated output
├── css/
│ └── variables.css
├── ios/
│ └── StyleDictionary.swift
└── android/
└── colors.xml
style-dictionary.config.js
配置
基本配置
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
},
],
},
},
};
多平台配置
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
// Web - CSS Custom Properties
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
options: {
outputReferences: true, // Keep token references
},
},
],
},
// Web - SCSS Variables
scss: {
transformGroup: 'scss',
buildPath: 'build/scss/',
files: [
{
destination: '_variables.scss',
format: 'scss/variables',
},
],
},
// Web - JavaScript/TypeScript
js: {
transformGroup: 'js',
buildPath: 'build/js/',
files: [
{
destination: 'tokens.js',
format: 'javascript/es6',
},
{
destination: 'tokens.d.ts',
format: 'typescript/es6-declarations',
},
],
},
// iOS - Swift
ios: {
transformGroup: 'ios-swift',
buildPath: 'build/ios/',
files: [
{
destination: 'StyleDictionary.swift',
format: 'ios-swift/class.swift',
className: 'StyleDictionary',
},
],
},
// Android - XML Resources
android: {
transformGroup: 'android',
buildPath: 'build/android/',
files: [
{
destination: 'colors.xml',
format: 'android/colors',
filter: { type: 'color' },
},
{
destination: 'dimens.xml',
format: 'android/dimens',
filter: { type: 'dimension' },
},
],
},
},
};
令牌格式
Design Tokens Community Group(DTCG)格式
{
"color": {
"primary": {
"$value": "#3b82f6",
"$type": "color",
"$description": "Primary brand color"
},
"secondary": {
"$value": "#64748b",
"$type": "color"
}
},
"spacing": {
"sm": {
"$value": "8px",
"$type": "dimension"
},
"md": {
"$value": "16px",
"$type": "dimension"
}
}
}
Style Dictionary 经典格式
{
"color": {
"primary": {
"value": "#3b82f6",
"type": "color",
"comment": "Primary brand color"
}
},
"spacing": {
"sm": { "value": "8px" },
"md": { "value": "16px" }
}
}
令牌引用(别名)
{
"color": {
"base": {
"blue": {
"500": { "value": "#3b82f6" }
}
},
"primary": {
"value": "{color.base.blue.500}"
},
"button": {
"background": {
"value": "{color.primary}"
}
}
}
}
自定义转换
注册自定义转换
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');
// Transform px to rem
StyleDictionary.registerTransform({
name: 'size/pxToRem',
type: 'value',
matcher: (token) => token.type === 'dimension',
transformer: (token) => {
const px = parseFloat(token.value);
return `${px / 16}rem`;
},
});
// Transform color to OKLCH
StyleDictionary.registerTransform({
name: 'color/oklch',
type: 'value',
matcher: (token) => token.type === 'color',
transformer: (token) => {
// Use a color library like culori
const { formatCss, oklch, parse } = require('culori');
return formatCss(oklch(parse(token.value)));
},
});
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transforms: [
'attribute/cti',
'name/cti/kebab',
'size/pxToRem', // Custom
'color/oklch', // Custom
],
buildPath: 'build/css/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
},
],
},
},
};
常见自定义转换
// Clamp font sizes for fluid typography
StyleDictionary.registerTransform({
name: 'size/fluidType',
type: 'value',
matcher: (token) => token.attributes?.category === 'font' && token.attributes?.type === 'size',
transformer: (token) => {
const min = parseFloat(token.value) * 0.875;
const max = parseFloat(token.value);
return `clamp(${min}rem, 2vw + 1rem, ${max}rem)`;
},
});
// Shadow to CSS format
StyleDictionary.registerTransform({
name: 'shadow/css',
type: 'value',
matcher: (token) => token.type === 'shadow',
transformer: (token) => {
const { x, y, blur, spread, color } = token.value;
return `${x}px ${y}px ${blur}px ${spread}px ${color}`;
},
});
自定义格式
支持深色模式的 CSS
StyleDictionary.registerFormat({
name: 'css/variables-themed',
formatter: ({ dictionary, options }) => {
const lightTokens = dictionary.allTokens
.filter(t => !t.path.includes('dark'))
.map(t => ` --${t.name}: ${t.value};`)
.join('\n');
const darkTokens = dictionary.allTokens
.filter(t => t.path.includes('dark'))
.map(t => {
const name = t.name.replace('dark-', '');
return ` --${name}: ${t.value};`;
})
.join('\n');
return `:root {\n${lightTokens}\n}\n\n[data-theme="dark"] {\n${darkTokens}\n}`;
},
});
Tailwind 配置格式
StyleDictionary.registerFormat({
name: 'tailwind/config',
formatter: ({ dictionary }) => {
const colors = {};
const spacing = {};
dictionary.allTokens.forEach(token => {
if (token.type === 'color') {
const path = token.path.slice(1).join('-');
colors[path] = token.value;
}
if (token.type === 'dimension' && token.path[0] === 'spacing') {
spacing[token.path[1]] = token.value;
}
});
return `module.exports = {
theme: {
extend: {
colors: ${JSON.stringify(colors, null, 2)},
spacing: ${JSON.stringify(spacing, null, 2)},
},
},
};`;
},
});
多主题设置
令牌结构
tokens/
├── core/
│ ├── colors.json # Primitives (blue-500, gray-100)
│ └── spacing.json
├── semantic/
│ ├── light.json # Semantic mappings for light
│ └── dark.json # Semantic mappings for dark
└── brand/
├── default.json # Default brand
└── partner.json # White-label brand
主题专属配置
// style-dictionary.config.js
const themes = ['light', 'dark'];
const brands = ['default', 'partner'];
module.exports = {
source: ['tokens/core/**/*.json'],
platforms: brands.flatMap(brand =>
themes.map(theme => ({
[`css-${brand}-${theme}`]: {
transformGroup: 'css',
buildPath: `build/${brand}/`,
files: [
{
destination: `${theme}.css`,
format: 'css/variables',
filter: (token) =>
token.filePath.includes('core') ||
token.filePath.includes(theme),
},
],
source: [
`tokens/semantic/${theme}.json`,
`tokens/brand/${brand}.json`,
],
},
}))
),
};
构建流水线集成
package.json 脚本
{
"scripts": {
"tokens:build": "style-dictionary build",
"tokens:watch": "style-dictionary build --watch",
"tokens:clean": "rm -rf build/",
"prebuild": "npm run tokens:build"
}
}
与 Figma Tokens 插件配合使用
# 1. Export from Figma Tokens plugin to tokens/figma.json
# 2. Transform with Style Dictionary
npx token-transformer tokens/figma.json tokens/transformed.json
style-dictionary build
GitHub Action
# .github/workflows/tokens.yml
name: Build Tokens
on:
push:
paths:
- 'tokens/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run tokens:build
- uses: actions/upload-artifact@v4
with:
name: tokens
path: build/
输出示例
输入令牌
{
"color": {
"primary": {
"value": "#3b82f6",
"type": "color"
}
}
}
CSS 输出
:root {
--color-primary: #3b82f6;
}
SCSS 输出
$color-primary: #3b82f6;
JavaScript 输出
export const ColorPrimary = '#3b82f6';
iOS Swift 输出
public class StyleDictionary {
public static let colorPrimary = UIColor(red: 0.231, green: 0.510, blue: 0.965, alpha: 1.0)
}
Android XML 输出
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<color name="color_primary">#3b82f6</color>
</resources>
常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 循环引用 | 检查令牌别名是否形成循环 |
| 未找到令牌 | 确认引用中的路径完全匹配 |
| 输出格式错误 | 检查转换组是否与平台匹配 |
| 缺少令牌 | 检查 filter 是否将其排除 |
| 构建结果过时 | 构建前运行 tokens:clean |
Style Dictionary v4(最新版本)
// style-dictionary.config.js (v4 syntax)
import StyleDictionary from 'style-dictionary';
export default {
source: ['tokens/**/*.json'],
preprocessors: ['tokens-studio'], // For Figma Tokens
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/',
files: [{
destination: 'variables.css',
format: 'css/variables',
}],
},
},
};
# Run with ESM
node --experimental-json-modules ./node_modules/.bin/style-dictionary build
评论
支持 Markdown