Files
obsidian-vault/projects/frontend/design-tokens-guidelines.md
yuxuanhui 91861565bb feat: add frontend development guidelines and structure documentation
- Introduced API guidelines for interface contracts and request handling.
- Added design tokens usage guidelines for consistent styling across the project.
- Established DTO guidelines for defining request parameters and response data types.
- Created frontend structure guidelines to clarify directory organization and code placement rules.
- Compiled a comprehensive frontend development guideline document covering various aspects of the development process.
- Implemented quality guidelines to ensure code maintainability and adherence to best practices.
2026-07-25 22:20:25 +08:00

6.4 KiB

设计变量使用规范

基于 @oppein-react/design-tokens 的前端样式实现规范。


目标

本规范用于统一项目中颜色、间距、字体、圆角、阴影和主题语义变量的使用方式,避免出现以下问题:

  • 同一项目内同时混用 token、硬编码 HEX 和临时样式值
  • 视觉稿已统一,但代码层无法稳定复用设计变量
  • 亮暗主题切换时,组件样式无法跟随语义变量变化
  • 业务组件直接依赖底层常量,导致样式难以替换和升级

核心原则:

  1. 业务样式优先消费 CSS 变量或 UnoCSS token class
  2. 语义优先于具体色值,优先写 var(--op-primary) 而不是固定品牌阶值
  3. 亮暗主题切换统一通过 .dark 类名驱动,不在组件内自行维护双份颜色
  4. TypeScript token 常量仅用于脚本、配置、图表主题等非 CSS 场景

安装与接入

包安装

  • 外部项目需要先配置 npm registry,再安装 @oppein-react/design-tokens
  • monorepo 内部 workspace 包,依赖统一写成 "@oppein-react/design-tokens": "workspace:*"
  • 设计变量包是叶子包,不应再反向依赖业务包

CSS 注入

  • 应用入口必须导入 @oppein-react/design-tokens/css
  • 入口导入只能做一次,避免在页面组件或局部样式文件重复注入
  • 推荐放在 src/main.ts 或应用级入口文件

示例:

import "@oppein-react/design-tokens/css";

样式消费规则

1. CSS 变量

适用场景:

  • 组件样式文件
  • CSS Modules
  • 全局样式
  • 需要跟随暗色主题自动切换的颜色、阴影、背景、边框

规则:

  • 全局 CSS 变量统一使用 --op- 前缀
  • 颜色优先使用语义变量,如 --op-primary、--op-background、--op-foreground
  • 只有在明确需要某个色板阶值时,才使用 --op-color-brand-6 这类全局色板变量
  • 间距、圆角、阴影统一使用 token 变量,不要自己再写一套近似值

示例:

.page {
  color: var(--op-foreground);
  background: var(--op-background);
}

.primary-button {
  color: var(--op-color-white);
  background: var(--op-primary);
  border-radius: var(--op-radius-button);
  box-shadow: var(--op-shadow-1);
  padding: var(--op-spacing-xs) var(--op-spacing-sm);
}

2. UnoCSS token class

适用场景:

  • 项目已经启用 UnoCSS
  • 样式以原子类为主,且希望直接映射设计 token

规则:

  • uno.config.ts 中统一启用 presetOppein()
  • 业务代码直接使用 token class,如 bg-background、text-foreground、rounded-card
  • 不要一边启用 preset,一边继续大面积写无语义的颜色 class 或硬编码 style
  • 如需覆盖品牌主色,可在 presetOppein({ primary }) 中配置,不在业务组件中零散覆盖

示例:

import { defineConfig, presetUno } from "unocss";
import { presetOppein } from "@oppein-react/design-tokens/unocss";

export default defineConfig({
  presets: [presetUno(), presetOppein()],
});
export function Example() {
  return (
    <div className="bg-background text-foreground p-md rounded-card">
      <button className="bg-primary text-white px-sm py-xs rounded-button">
        保存
      </button>
    </div>
  );
}

变量选择顺序

新增样式时,按以下顺序选择 token:

  1. 先找语义变量 例如:--op-primary、--op-background-secondary、--op-border
  2. 再找语义尺寸变量 例如:--op-spacing-md、--op-radius-card、--op-shadow-2
  3. 最后才使用全局色板阶值 例如:--op-color-brand-6

只有在以下场景允许直接使用色板阶值:

  • 图表配色
  • 特殊插画或装饰性视觉
  • 设计稿明确指定阶值,而不是语义角色

主题切换规则

  • 亮色主题默认挂在 :root
  • 暗色主题统一挂在 .dark
  • 切换主题时,只允许操作根节点的 dark 类名
  • 禁止在业务组件内通过条件分支手写两套 HEX 颜色实现明暗主题

示例:

document.documentElement.classList.toggle("dark", isDark);

TypeScript 常量使用边界

@oppein-react/design-tokens 导出的 colors、spacing、radius、shadows、lightTheme、darkTheme 适用于:

  • 图表主题
  • JS 配置对象
  • 运行时计算
  • 非 CSS 场景的默认值或映射表

禁止把这些常量当作业务组件样式的默认写法,尤其不要在 JSX 内直接硬塞原始色值:

import { colors, lightTheme, radius, spacing } from "@oppein-react/design-tokens";

const primary = colors.brand[6];
const pageBackground = lightTheme.background;
const cardRadius = radius.card;
const gap = spacing.md;

禁止行为

  • 在组件、页面、全局样式中硬编码颜色值,如 #3370FF、rgba(0,0,0,.12),而对应 token 已存在
  • 新增一套项目私有的 --primary、--brand-blue 之类变量,与 --op- 体系并行
  • 在组件内部手动维护亮色和暗色两套颜色常量
  • CSS 变量已经能表达的场景,仍在 JS 中拼接大量内联样式对象
  • 为了局部视觉效果随意创造规范外阴影、圆角和间距值

Wrong vs Correct

颜色

Wrong

.tab-active {
  color: #3370ff;
  border-color: #3370ff;
}

Correct

.tab-active {
  color: var(--op-primary);
  border-color: var(--op-primary);
}

圆角与阴影

Wrong

.card {
  border-radius: 15px;
  box-shadow: 0 6px 18px rgba(17, 26, 44, 0.08);
}

Correct

.card {
  border-radius: var(--op-radius-card);
  box-shadow: var(--op-shadow-2);
}

主题切换

Wrong

const style = {
  color: isDark ? "#ffffff" : "#1f2329",
  background: isDark ? "#141414" : "#ffffff",
};

Correct

document.documentElement.classList.toggle("dark", isDark);
.panel {
  color: var(--op-foreground);
  background: var(--op-background);
}

开发与验收清单

提交前至少确认:

  • 入口是否已注入 @oppein-react/design-tokens/css
  • 颜色、圆角、阴影、间距是否优先使用了 --op- 变量
  • 可用语义变量时,是否避免了直接写色板阶值
  • 是否避免新增硬编码 HEX、RGB、RGBA
  • 暗色模式是否通过 .dark 驱动,而不是组件局部条件分支
  • 项目启用 UnoCSS 时,是否已优先使用 token class 而非重复造 class

相关规范

  • 视觉语义与组件形态:DESIGN.md
  • 目录和样式归属:frontend-structure-guidelines.md
  • 提交前检查:quality-guidelines.md