Eonova Design Tokens
以 CSS 变量为契约的
设计令牌系统
一份 SSOT,三端适配。颜色与形状值只定义一次,排版刻度独立成层,夜间主题由
--eonova-* 变量与 [data-theme="dark"] 级联决定。
01 · 颜色系统
颜色系统
语义令牌按用途命名(primary / surface / text-muted…),light 与 dark 各一套值; 品牌与中性色阶供构建期引用。任何场景下颜色都不写死,只引用变量。
语义令牌
品牌色阶 · brand
中性色阶 · neutral
02 · 字体系统
字体系统
三套字体栈各司其职:Display 用于标题、Sans 用于正文与界面、Mono 用于代码与数据; 中文统一回退 Noto Sans SC。字号 / 行高 / 字距 / 字重全部刻度化。
字体栈
--eonova-font-display
Eonova Display · 设计标题 0123
--eonova-font-sans
Eonova Sans · 正文界面,中文回退验证:设计令牌。
--eonova-font-mono
const theme = "dark"; // Reddit Mono · tnum 1234567890
字号刻度
字体阵容
Aa 字
Space Grotesk · Display
标题字形:几何感强、字腔开阔;自托管 latin 子集,wght 300–700。
Aa 字
Nunito · Sans
正文与界面:圆润亲和;可变字重 200–1000,正文到强调一档不缺。
</>
Reddit Mono · Mono
代码与数据:x 高度大、易读,内置 tnum 等宽数字,wght 100–900。
永
Noto Sans SC · CJK
中文回退:npm unicode-range 分片按需加载,可变字重与西文对齐。
等宽数字 tnum
tnum + zero(数据列对齐推荐)
总量 12,345,670 增量 9,876,541 余额 1,234,567
默认比例数字
总量 12,345,670 增量 9,876,541 余额 1,234,567
字重刻度
行高刻度
字距刻度
03 · 动画效果
动画效果
时长刻度决定过渡的节奏,缓动曲线决定运动的性格;instant 仅用于开关类状态,不参与过渡。 下方演示循环播放,直观对比各档差异。
时长刻度 · duration
缓动曲线 · easing
04 · 间距与形
间距与形
4px 基线的间距刻度、克制的圆角语言与三层阴影构成全部深度表达,dark 模式下阴影自动加重。
圆角
阴影
间距
05 · 原子组件
原子组件
令牌组合出的最小可用单元:按钮、徽章、引用、代码块、表格与分隔符。 组件不引入新的颜色与圆角,全部由语义令牌拼装,可被三端适配层等价表达。
按钮
徽章
Quote
好内容,值得好版面。设计系统是给内容做减法,不是给页面做加法。
Code Block
const theme = "dark";
表格
| 刻度 | 值 |
|---|---|
| radius-md | 8px |
| radius-lg | 12px |
分隔符
06 · 设计原则
设计原则与风格定位
Eonova 是一套「契约先行」的设计令牌系统:值只定义一次,消费端只认变量。 风格上追求克制、清晰、工程友好——把每个决定都变成可被三端复用的刻度。
设计原则
01
单一事实来源
颜色与形状值只在 packages/tokens 定义,字体与排版只在 packages/fonts 定义;适配器源码中禁止出现静态值。改一处,三端同时生效。
02
运行时只认 CSS 变量
主题契约是 --eonova-* 变量 + [data-theme="dark"] 级联。适配层只是「变量引用的翻译器」,不引入第二套运行时机制,主题切换零成本。
03
一切皆刻度
间距锚定 4px 基线,字号 / 字重 / 行高 / 字距 / 时长全部档位化,不给「随手写一个 13px」留余地,保证跨项目视觉节奏一致。
04
按用途命名
语义令牌叫 color.primary / color.text-muted,而不是 blue-500。换主题、换品牌时,消费端代码一行不改。
风格定位
克制
Restrained
三层阴影 + 单色边框构成全部深度表达,不堆叠投影与渐变;dark 模式下阴影自动加重补偿对比。
文档感
Editorial
编号分节 + 单栏叙事 + 示例卡节奏,让令牌系统像一份可阅读的规范,而不是组件橱窗。
夜间优先
Dark-first
默认主题为 data-theme="dark",深色下重新校准语义色与阴影层次;light 作为同构的另一套值共存于同一份 SSOT。
07 · 决策速查
决策速查
根据用途选择令牌与组件,表中未列出的情况参考前面的设计原则。
| 要做什么 | 怎么做 |
|---|---|
| 标题排版 | font-display + tracking-tight,字号按层级刻度取档 |
| 正文阅读 | font-sans text-base,行高 leading-normal |
| 强调一个数字 | color-primary + tnum,不额外加粗 |
| 分隔两段内容 | 先用留白;边界必须明确时,才用两端渐隐的细线 |
| 区分主次按钮 | Primary 品牌色填充;Secondary 描边幽灵样式 |
| 标注状态 | badge 徽章三色:默认 / success / danger |
| 展示代码 | surface 底 + 小圆角 + mono 字体,无边框 |
| 微交互时长 | duration-fast;面板展开用 normal / slow |
| 入场与退场 | 入场 easing-decelerate,退场 easing-accelerate |
| 切换夜间主题 | 根元素声明 data-theme="dark",全部语义色随级联生效 |
| 接入令牌系统 | 原生 CSS 变量契约 + Tailwind / UnoCSS / StyleX 三端适配层 |
08 · 反面示例
反面示例
常见的用法偏差与对应的正确做法。左列是令牌系统要消灭的写法,右列是唯一的推荐路径。
| 反面示例 | 正确做法 |
|---|---|
| 写死色值 #6366f1 | 只用 var(--eonova-color-primary) 等语义变量 |
| 随手一个 13px 字号 | 从字号刻度取档,不设中间值 |
| 按外观命名 blue-500 | 按用途命名 color.primary / color.text-muted |
| 多层阴影堆叠强调 | 三层阴影刻度内选一档,不叠加 |
| 随手一个 300ms 动画 | duration 三档 + easing 三曲线内取值 |
| 满屏卡片盒子 | 用留白分组;分割线只出现在分节之间 |