刚学前端时候,我以为 CSS 变量就是 var(--primary-color) 替代 #6d28d9—换个地方写颜色值而已。
后来重构博客样式,我才意识到:把所有颜色、间距、圆角集中定义在一处,改一个值全站联动—这比满文件搜索替换 #6d28d9 靠谱太多了。
这篇文章记录我在实际项目中用 CSS 变量管理设计系统过程。
设计 Token:给设计取名字
设计 Token 就是给设计决策取个名字。我的博客定义了五类:
颜色
:root {
/* 主色 */
--color-primary: #425AEF;
--color-primary-light: #6B7FF5;
--color-primary-dark: #3149D1;
/* 语义色 */
--color-success: #22c55e;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* 中性色 */
--color-text: #2c2c2c;
--color-text-secondary: #666;
--color-text-muted: #999;
--color-border: #e5e7eb;
/* 背景层次 */
--bg-body: #f5f6f8;
--bg-card: #ffffff;
--bg-elevated: #ffffff;
}
命名用语义而不是颜色值:--color-text 比 --gray-900 好。暗色模式下文字颜色会变,但”正文文字”这个语义不会变。
间距
:root {
--gap-xs: 4px;
--gap-sm: 8px;
--gap-md: 16px;
--gap-lg: 24px;
--gap-xl: 32px;
--gap-2xl: 48px;
--gap-3xl: 64px;
}
4px 倍数步长。以前随手写 margin: 13px,现在不会再出现了。
字体
:root {
--font-sans: 'Noto Sans SC', system-ui, sans-serif;
--font-serif: 'Noto Serif SC', Georgia, serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
}
圆角与阴影
:root {
--radius-sm: 6px;
--radius-md: 14px;
--radius-lg: 20px;
--radius-full: 9999px;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
}
暗色模式:换个值就行
暗色模式有两种做法:CSS 变量切换和 prefers-color-scheme 媒体查询。
我选变量切换,因为可以手动切换,不只跟系统走:
[data-theme="dark"] {
--color-text: #d8d8e4;
--color-text-secondary: #a0a0b0;
--color-text-muted: #6b6b7b;
--color-border: #2d2d3d;
--bg-body: #1a1a2e;
--bg-card: #252540;
--bg-elevated: #2d2d4a;
}
切换主题改一个属性就行:
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
暗色模式有几个容易踩坑:
- 别用纯白。
#fff在深色背景上太刺眼,#d8d8e4舒服得多 - 背景加色温。纯黑
#000太冷,偏蓝紫#1a1a2e更柔和 - 阴影降透明度。暗色模式下阴影要更微妙
- 边框降对比。暗色边框与背景对比度应该比浅色模式低
间距一致性
重构前代码:
.hero { margin-bottom: 48px; }
.section { padding: 24px; }
.card { padding: 16px; gap: 8px; }
.footer { margin-top: 60px; } /* 60px? 为什么不是 64px? */
重构后:
.hero { margin-bottom: var(--gap-2xl); }
.section { padding: var(--gap-lg); }
.card { padding: var(--gap-md); gap: var(--gap-sm); }
.footer { margin-top: var(--gap-3xl); }
60px 变成了 64px(--gap-3xl),肉眼看不出区别,但以后维护不需要猜”这个 60px 是怎么来”。
常见误区
所有值都用变量
一次性值(如 top: -2px)用硬编码更清晰。变量的意义在于复用和统一,不是变量越多越好。
嵌套变量过深
/* 调试噩梦 */
--color-primary: var(--blue-500);
--blue-500: var(--blue-base);
--blue-base: #425AEF;
最多一层间接引用。设计 Token 应该是扁平。
忽略 fallback
如果受众包含旧浏览器用户,提供 fallback:
.hero {
color: #2c2c2c; /* fallback */
color: var(--color-text); /* 现代浏览器覆盖 */
}
实际效果
改完之后,我调主色调只需要改 --color-primary 一个值。改间距只需要调 --gap-*。暗色模式加一组变量覆盖就完事。
以前改个主色要全局搜索替换十几个文件,现在改一行。这就是变量化好处:省事,且不容易漏。
COMMENTS
种下你的想法
在花园里留下一条评论,和这篇文章一起生长。