多品牌与白标主题
令牌分层、品牌资产管线、多租户产品的运行时主题切换。
设计系统高级
为什么
硬编码品牌色意味着新租户需 fork 和 3 个月发布。令牌分层主题让你数小时上线白标品牌,仅换一个令牌文件,零代码分支。
根据 2024 Spark 设计系统调查,78% 拥有设计系统的组织报告产品交付更快。JavaScript is used by 62% of developers per the Stack Overflow 2024 survey,与设计令牌对齐的组件库将交接时间缩短 60%。
何时使用
有 2+ 品牌或任何白标/代理用例时构建多品牌主题。别为 '也许有一天' 投机构建 — 抽象税不值。
如何做
1. 令牌分层 — 原始(blue-500)、语义(action-primary)、品牌(logo、字体)
2. 品牌包 — 每品牌发布 tokens.{brand}.json + assets/(logo、字体)
3. 构建管线 — Style Dictionary 每品牌输出一组 CSS 变量到 /dist/brands/{brand}.css
4. 运行时切换 — 在 <html data-brand="acme"> 加载品牌 CSS 文件,变量级联
5. 组件代码 — 引用 var(--color-action-primary),绝不品牌特定值
6. 资产管线 — 品牌 logo 通过 next/image,品牌作用域 public/brands/{brand}/
7. 测试矩阵 — Storybook 在 CI 中每品牌渲染每组件
示例
// tokens/acme.json — 品牌覆盖
{
"color.action.primary": "{color.blue.600}",
"font.family.body": "AcmeSans, sans-serif",
"asset.logo": "/brands/acme/logo.svg"
}
// ThemeSwitcher.tsx — 运行时品牌加载
function ThemeSwitcher({ brand }: { brand: "acme" | "globex" }) {
useEffect(() => {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = `/brands/${brand}.css`;
document.head.appendChild(link);
document.documentElement.dataset.brand = brand;
return () => link.remove();
}, [brand]);
return null;
}
/* brands/acme.css — Style Dictionary 输出 */
:root[data-brand="acme"] {
--color-action-primary: #2563eb;
--font-family-body: "AcmeSans", sans-serif;
}
常见问题
- ⚠品牌特定值泄漏进组件 — Button 硬编码 Acme 蓝,Globex 得到蓝按钮
- ⚠前置加载所有品牌 CSS — 10 品牌 × 50KB = 500KB 客户端浪费
- ⚠无品牌测试矩阵 — Acme 正常但 Globex 对比破损,生产中发现
最佳实践
- ✓组件仅引用语义令牌 — 绝不原始或品牌特定值
- ✓懒加载品牌 CSS — 运行时注入活跃租户的那一个样式表
- ✓Storybook 渲染品牌矩阵 — CI chromatic 快照中每组件 × 每品牌