话题 6:命名规范深度探讨
本文是「设计系统与 Tailwind CSS 深度实践」系列的最后一篇,深入探讨 Token 命名的哲学、流派与最佳实践。
一、为什么命名如此重要?
1.1 命名的三重影响
| 影响维度 | 说明 |
|---|---|
| 可读性 | 开发者能否快速理解这个 Token 的用途 |
| 可维护性 | 修改/扩展时是否容易定位和调整 |
| 设计师理解成本 | 设计师能否直接理解代码中的命名 |
1.2 一个命名失败的案例
css
/* 糟糕的命名 */
:root {
--c1: #3B82F6;
--c2: #EF4444;
--main-color: #111827;
--sub: #6B7280;
--bg: #FFFFFF;
--bgAlt: #F9FAFB;
}问题:
--c1、--c2完全无语义--main-color和--sub是什么的 main/sub?--bg和--bgAlt的区别是什么?- 大小写不一致(
bgAltvsmain-color)
好的命名应该让代码"自解释"。
二、三大命名流派深度分析
2.1 流派一:数值型(Primitive-focused)
特点:以具体数值或刻度命名
css
/* 颜色 */
--color-blue-50: #EFF6FF;
--color-blue-500: #3B82F6;
--color-blue-900: #1E3A8A;
/* 间距 */
--space-1: 4px;
--space-2: 8px;
--space-4: 16px;
/* 字号 */
--text-sm: 14px;
--text-base: 16px;
--text-lg: 18px;优点:
- 无歧义,100 就是比 200 浅
- 与 Tailwind 默认命名一致
- 扩展容易(可以加 150、250 等中间值)
缺点:
- 无使用语义(
blue-500用在哪?) - 主题切换困难(暗黑模式下
blue-500该变成什么?) - 设计师需要记忆数字含义
适用场景:Primitive Token 层
2.2 流派二:语义型(Semantic-focused)
特点:以使用场景/语义命名
css
/* 背景 */
--color-bg-primary: #FFFFFF;
--color-bg-secondary: #F9FAFB;
--color-bg-inverse: #111827;
/* 文字 */
--color-text-primary: #111827;
--color-text-secondary: #6B7280;
--color-text-muted: #9CA3AF;
/* 边框 */
--color-border-default: #E5E7EB;
--color-border-emphasis: #3B82F6;
/* 交互状态 */
--color-interactive-primary: #3B82F6;
--color-interactive-primary-hover: #2563EB;优点:
- 语义清晰,知道用在哪
- 主题切换友好(切换映射即可)
- 设计师易理解
缺点:
- 命名难度高(什么是 primary vs secondary?)
- 可能出现命名爆炸
- 边界模糊(这个蓝色是
primary还是brand?)
适用场景:Semantic Token 层
2.3 流派三:组件型(Component-focused)
特点:精确到具体组件和状态
css
/* Button */
--button-primary-bg: #3B82F6;
--button-primary-bg-hover: #2563EB;
--button-primary-bg-active: #1D4ED8;
--button-primary-bg-disabled: #E5E7EB;
--button-primary-text: #FFFFFF;
--button-primary-text-disabled: #9CA3AF;
/* Input */
--input-bg: #FFFFFF;
--input-border: #E5E7EB;
--input-border-focus: #3B82F6;
--input-border-error: #EF4444;
--input-text: #111827;
--input-placeholder: #9CA3AF;优点:
- 精确无歧义
- 组件完全自包含
- 修改影响范围明确
缺点:
- Token 数量爆炸
- 维护成本高
- 复用困难(按钮和卡片都想用同一个蓝色怎么办?)
适用场景:大型设计系统的 Component Token 层
2.4 三种流派对比总结
| 维度 | 数值型 | 语义型 | 组件型 |
|---|---|---|---|
| 可读性 | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 灵活性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| 主题支持 | ⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Token 数量 | 少 | 中 | 多 |
| 维护成本 | 低 | 中 | 高 |
| 设计师友好 | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
三、我的推荐:分层混合策略
3.1 核心原则
不同层用不同命名策略:
| 层级 | 命名策略 | 示例 |
|---|---|---|
| Primitive | 数值型 | blue-500, gray-100, space-4 |
| Semantic | 语义型 | bg-primary, text-muted, border-default |
| Component | 组件型(可选) | button-primary-bg-hover |
3.2 命名结构规范
通用结构:{category}-{property}-{variant}-{state}
category: color, space, size, radius, shadow, font, ...
property: bg, text, border, ring, ...
variant: primary, secondary, muted, success, error, ...
state: default, hover, active, disabled, focus, ...3.3 完整命名体系示例
Primitive Layer(数值型)
├── color-blue-50 ... color-blue-950
├── color-gray-50 ... color-gray-950
├── color-red-50 ... color-red-700
├── color-green-50 ... color-green-700
├── space-0 ... space-96
├── radius-none, radius-sm, radius-md, radius-lg, radius-full
└── shadow-sm, shadow-md, shadow-lg, shadow-xl
Semantic Layer(语义型)
├── Color - Background
│ ├── color-bg (默认背景)
│ ├── color-bg-secondary (次级背景)
│ ├── color-bg-tertiary (三级背景)
│ ├── color-bg-inverse (反转背景)
│ └── color-bg-overlay (遮罩背景)
│
├── Color - Text
│ ├── color-text (默认文字)
│ ├── color-text-muted (弱化文字)
│ ├── color-text-subtle (更弱文字)
│ ├── color-text-inverse (反转文字)
│ └── color-text-on-primary (主色上的文字)
│
├── Color - Border
│ ├── color-border (默认边框)
│ ├── color-border-muted (弱化边框)
│ └── color-border-emphasis (强调边框)
│
├── Color - Interactive
│ ├── color-primary (主要交互色)
│ ├── color-primary-hover
│ ├── color-primary-active
│ ├── color-secondary (次要交互色)
│ └── color-accent (强调色)
│
├── Color - Status
│ ├── color-success / color-success-bg / color-success-text
│ ├── color-warning / color-warning-bg / color-warning-text
│ ├── color-error / color-error-bg / color-error-text
│ └── color-info / color-info-bg / color-info-text
│
└── Color - Misc
├── color-ring (焦点环)
└── color-shadow (阴影色)四、常见命名争议与我的立场
4.1 争议 1:primary 还是 brand?
css
/* 方案 A: primary */
--color-primary: #3B82F6;
/* 方案 B: brand */
--color-brand: #3B82F6;我的立场:用 primary
理由:
primary是 UI 语境,描述"最重要的交互色"brand是营销语境,可能有多个品牌色- Tailwind、shadcn/ui、Radix 等主流方案都用
primary - 更通用,不绑定具体品牌概念
4.2 争议 2:default 还是省略?
css
/* 方案 A: 显式 default */
--color-bg-default: #FFFFFF;
--color-bg-secondary: #F9FAFB;
/* 方案 B: 省略 default */
--color-bg: #FFFFFF;
--color-bg-secondary: #F9FAFB;我的立场:省略 default
理由:
- 更简洁
default是隐含的- Tailwind 的
DEFAULT就是这个思路(bg-background而非bg-background-default)
4.3 争议 3:kebab-case 还是 camelCase?
css
/* 方案 A: kebab-case */
--color-bg-primary: #FFFFFF;
/* 方案 B: camelCase */
--colorBgPrimary: #FFFFFF;我的立场:CSS 变量用 kebab-case,JS 对象用 camelCase
css
/* CSS */
--color-bg-primary: #FFFFFF;javascript
// JavaScript
const tokens = {
color: {
bgPrimary: '#FFFFFF',
}
};理由:
- 遵循各语言的惯例
- CSS 变量用 kebab-case 是 CSS 的标准风格
- 构建工具可以自动转换
4.4 争议 4:嵌套层级多深合适?
css
/* 方案 A: 扁平 */
--button-primary-bg-hover: #2563EB;
/* 方案 B: 嵌套(用对象表示) */
button.primary.bg.hover: #2563EB我的立场:语义层最多 3 级,组件层最多 4 级
语义层:{category}-{property}-{variant}
color-bg-secondary ✅
color-bg-secondary-hover ❌ (hover 应该在组件层)
组件层:{component}-{variant}-{property}-{state}
button-primary-bg-hover ✅
button-primary-outline-bg-hover ❌ (太深了)五、实战命名规范手册
5.1 颜色命名
✅ 推荐命名
背景色:
- background / bg-secondary / bg-tertiary / bg-inverse
- bg-overlay (遮罩)
- bg-raised (浮起,如卡片)
文字色:
- foreground / text-muted / text-subtle / text-inverse
- text-on-primary (主色按钮上的文字)
边框色:
- border / border-muted / border-emphasis
交互色:
- primary / primary-foreground
- secondary / secondary-foreground
- accent / accent-foreground
状态色:
- destructive / destructive-foreground (或 error)
- success / success-foreground
- warning / warning-foreground
❌ 避免的命名
- main, sub (太模糊)
- color1, color2 (无语义)
- light-blue, dark-gray (混淆 primitive 和 semantic)
- btn-color (缩写不一致)5.2 间距命名
✅ 推荐:数值刻度
space-0, space-1, space-2, space-3, space-4 ...
(基于 4px 基准:0, 4px, 8px, 12px, 16px ...)
✅ 也可以:语义别名(可选)
spacing-page-x (页面水平内边距)
spacing-page-y (页面垂直内边距)
spacing-stack-sm / md / lg (堆叠元素间距)
spacing-inline-sm / md / lg (行内元素间距)
❌ 避免
spacing-small (small 是多少?)
padding-1 (把 padding 和 space 混淆)5.3 字体命名
✅ 推荐
字号:text-xs, text-sm, text-base, text-lg, text-xl ...
字重:font-normal, font-medium, font-semibold, font-bold
字族:font-sans, font-mono, font-serif
行高(可以绑定到字号):
fontSize: {
sm: ['14px', { lineHeight: '20px' }],
}
❌ 避免
font-size-1, font-size-2 (数字无含义)
font-big, font-bigger (相对概念)5.4 圆角命名
✅ 推荐
radius-none (0)
radius-sm (4px)
radius (6px,默认)
radius-md (8px)
radius-lg (12px)
radius-xl (16px)
radius-full (9999px)
❌ 避免
radius-1, radius-2 (数字无含义)
border-radius-small (太长)
rounded-4 (与 Tailwind 的 rounded 类混淆)5.5 阴影命名
✅ 推荐
shadow-sm
shadow (默认)
shadow-md
shadow-lg
shadow-xl
或者语义化:
shadow-raised (浮起效果)
shadow-overlay (弹层阴影)
shadow-inset (内阴影)六、完整命名规范参考表
6.1 CSS 变量命名规范
css
/* ================================================
命名规范参考
================================================
结构:--{category}-{property}-{variant}-{state}
category: color, space, size, radius, shadow, font
property: bg, text, border, ring
variant: primary, secondary, muted, success, error...
state: hover, active, disabled, focus (通常在组件层)
================================================ */
:root {
/* ============ Colors ============ */
/* Background */
--color-bg: 255 255 255;
--color-bg-secondary: 249 250 251;
--color-bg-tertiary: 243 244 246;
--color-bg-inverse: 17 24 39;
--color-bg-overlay: 0 0 0 / 0.5;
/* Text */
--color-text: 17 24 39;
--color-text-muted: 107 114 128;
--color-text-subtle: 156 163 175;
--color-text-inverse: 255 255 255;
/* Border */
--color-border: 229 231 235;
--color-border-muted: 243 244 246;
--color-border-emphasis: 59 130 246;
/* Interactive */
--color-primary: 59 130 246;
--color-primary-foreground: 255 255 255;
--color-secondary: 243 244 246;
--color-secondary-foreground: 17 24 39;
--color-accent: 99 102 241;
--color-accent-foreground: 255 255 255;
/* Status */
--color-success: 34 197 94;
--color-success-foreground: 255 255 255;
--color-warning: 234 179 8;
--color-warning-foreground: 255 255 255;
--color-error: 239 68 68;
--color-error-foreground: 255 255 255;
/* Misc */
--color-ring: 59 130 246;
}6.2 Tailwind 配置命名规范
javascript
// tailwind.config.js
module.exports = {
theme: {
colors: {
// Primitive (数值型,直接值)
blue: { 50: '...', 500: '...', 900: '...' },
gray: { 50: '...', 500: '...', 900: '...' },
// Semantic (语义型,CSS 变量)
background: {
DEFAULT: 'rgb(var(--color-bg) / <alpha-value>)',
secondary: 'rgb(var(--color-bg-secondary) / <alpha-value>)',
tertiary: 'rgb(var(--color-bg-tertiary) / <alpha-value>)',
},
foreground: {
DEFAULT: 'rgb(var(--color-text) / <alpha-value>)',
muted: 'rgb(var(--color-text-muted) / <alpha-value>)',
},
primary: {
DEFAULT: 'rgb(var(--color-primary) / <alpha-value>)',
foreground: 'rgb(var(--color-primary-foreground) / <alpha-value>)',
},
// ...
}
}
}七、你的组件库命名建议
基于你的场景(个人组件库 + 多主题 + React),我的具体建议:
7.1 采用两层命名
不需要组件层 Token(太复杂),两层足够:
Layer 1: Primitive(数值型)
├── 在 tailwind.config.js 中定义
├── 直接用 Tailwind 默认命名习惯
└── blue-500, gray-100, space-4 ...
Layer 2: Semantic(语义型)
├── 在 globals.css 中用 CSS 变量定义
├── 用于支持主题切换
└── background, foreground, primary, muted ...7.2 命名速查表
| 用途 | Tailwind Class | CSS 变量 |
|---|---|---|
| 默认背景 | bg-background | --color-bg |
| 次级背景 | bg-background-secondary | --color-bg-secondary |
| 默认文字 | text-foreground | --color-text |
| 弱化文字 | text-foreground-muted | --color-text-muted |
| 主要交互色 | bg-primary | --color-primary |
| 主色上的文字 | text-primary-foreground | --color-primary-foreground |
| 默认边框 | border-border | --color-border |
| 焦点环 | ring-ring | --color-ring |
| 错误状态 | text-destructive | --color-error |
| 成功状态 | text-success | --color-success |
7.3 使用示例
jsx
// 组件中这样使用
function Button({ variant = 'primary', children }) {
const variants = {
primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
outline: 'border border-border bg-background hover:bg-background-secondary',
ghost: 'hover:bg-background-secondary',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
};
return (
<button className={`px-4 py-2 rounded-md font-medium ${variants[variant]}`}>
{children}
</button>
);
}
// 页面中这样使用
function Page() {
return (
<div className="min-h-screen bg-background text-foreground">
<header className="border-b border-border p-4">
<h1 className="text-xl font-bold">Dashboard</h1>
</header>
<main className="p-6">
<div className="rounded-lg border border-border bg-background-secondary p-4">
<p className="text-foreground-muted">描述文字</p>
<Button variant="primary">确认</Button>
</div>
</main>
</div>
);
}八、系列总结
6 个话题核心要点回顾
| 话题 | 核心结论 |
|---|---|
| 1. Token 概念 | Token 是设计决策的最小单元,不是 CSS 变量;至少需要 Primitive + Semantic 两层 |
| 2. Tailwind 哲学 | 约束式设计带来一致性;config 就是 Primitive Token 层 |
| 3. 技术选型 | 推荐 Tailwind;Runtime CSS-in-JS 正在衰落 |
| 4. 多主题实现 | CSS 变量 + class 切换;用 RGB 格式支持透明度 |
| 5. 工程化方案 | 先用 TS 直接定义,成熟后引入 Style Dictionary |
| 6. 命名规范 | Primitive 用数值型,Semantic 用语义型;省略 default |
你的行动清单
立即可做:
- 创建
src/tokens/目录,定义 Primitive Token - 创建
src/styles/globals.css,定义语义化 CSS 变量 - 配置
tailwind.config.ts,引用 Token
- 创建
组件开发时:
- 使用语义化颜色(
bg-background、text-primary) - 不要硬编码颜色值(
bg-[#3B82F6]) - 封装可复用的变体(如 Button 的 variant)
- 使用语义化颜色(
未来演进:
- 引入 Style Dictionary 自动化构建
- 拆分 Monorepo 结构
- 考虑 Figma Token 同步
文件清单总览
src/
├── tokens/
│ ├── index.ts # 统一导出
│ ├── colors.ts # Primitive 颜色
│ ├── spacing.ts # 间距刻度
│ ├── typography.ts # 字体相关
│ └── semantic.ts # 语义化 Token(CSS 变量引用)
├── styles/
│ └── globals.css # CSS 变量定义(Light/Dark)
├── hooks/
│ └── useTheme.ts # 主题切换逻辑
├── components/
│ └── ...
└── tailwind.config.ts # Tailwind 配置结语
设计系统不是一蹴而就的,而是渐进演化的。
从最简单的方案开始:
- 先让主题切换跑起来
- 再逐步完善 Token 体系
- 最后考虑工程化和团队协作
完美是好的敌人。先有一个能用的系统,比有一个完美但从未实现的设计更有价值。
祝你的组件库项目顺利!🎉