273 lines
6.4 KiB
Markdown
273 lines
6.4 KiB
Markdown
|
|
# 设计变量使用规范
|
||
|
|
|
||
|
|
> 基于 `@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` 或应用级入口文件
|
||
|
|
|
||
|
|
示例:
|
||
|
|
|
||
|
|
```ts
|
||
|
|
import "@oppein-react/design-tokens/css";
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 样式消费规则
|
||
|
|
|
||
|
|
### 1. CSS 变量
|
||
|
|
|
||
|
|
适用场景:
|
||
|
|
|
||
|
|
- 组件样式文件
|
||
|
|
- CSS Modules
|
||
|
|
- 全局样式
|
||
|
|
- 需要跟随暗色主题自动切换的颜色、阴影、背景、边框
|
||
|
|
|
||
|
|
规则:
|
||
|
|
|
||
|
|
- 全局 CSS 变量统一使用 `--op-` 前缀
|
||
|
|
- 颜色优先使用语义变量,如 `--op-primary`、`--op-background`、`--op-foreground`
|
||
|
|
- 只有在明确需要某个色板阶值时,才使用 `--op-color-brand-6` 这类全局色板变量
|
||
|
|
- 间距、圆角、阴影统一使用 token 变量,不要自己再写一套近似值
|
||
|
|
|
||
|
|
示例:
|
||
|
|
|
||
|
|
```css
|
||
|
|
.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 })` 中配置,不在业务组件中零散覆盖
|
||
|
|
|
||
|
|
示例:
|
||
|
|
|
||
|
|
```ts
|
||
|
|
import { defineConfig, presetUno } from "unocss";
|
||
|
|
import { presetOppein } from "@oppein-react/design-tokens/unocss";
|
||
|
|
|
||
|
|
export default defineConfig({
|
||
|
|
presets: [presetUno(), presetOppein()],
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
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 颜色实现明暗主题
|
||
|
|
|
||
|
|
示例:
|
||
|
|
|
||
|
|
```ts
|
||
|
|
document.documentElement.classList.toggle("dark", isDark);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## TypeScript 常量使用边界
|
||
|
|
|
||
|
|
`@oppein-react/design-tokens` 导出的 `colors`、`spacing`、`radius`、`shadows`、`lightTheme`、`darkTheme` 适用于:
|
||
|
|
|
||
|
|
- 图表主题
|
||
|
|
- JS 配置对象
|
||
|
|
- 运行时计算
|
||
|
|
- 非 CSS 场景的默认值或映射表
|
||
|
|
|
||
|
|
禁止把这些常量当作业务组件样式的默认写法,尤其不要在 JSX 内直接硬塞原始色值:
|
||
|
|
|
||
|
|
```ts
|
||
|
|
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
|
||
|
|
|
||
|
|
```css
|
||
|
|
.tab-active {
|
||
|
|
color: #3370ff;
|
||
|
|
border-color: #3370ff;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Correct
|
||
|
|
|
||
|
|
```css
|
||
|
|
.tab-active {
|
||
|
|
color: var(--op-primary);
|
||
|
|
border-color: var(--op-primary);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 圆角与阴影
|
||
|
|
|
||
|
|
#### Wrong
|
||
|
|
|
||
|
|
```css
|
||
|
|
.card {
|
||
|
|
border-radius: 15px;
|
||
|
|
box-shadow: 0 6px 18px rgba(17, 26, 44, 0.08);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Correct
|
||
|
|
|
||
|
|
```css
|
||
|
|
.card {
|
||
|
|
border-radius: var(--op-radius-card);
|
||
|
|
box-shadow: var(--op-shadow-2);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 主题切换
|
||
|
|
|
||
|
|
#### Wrong
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
const style = {
|
||
|
|
color: isDark ? "#ffffff" : "#1f2329",
|
||
|
|
background: isDark ? "#141414" : "#ffffff",
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Correct
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
document.documentElement.classList.toggle("dark", isDark);
|
||
|
|
```
|
||
|
|
|
||
|
|
```css
|
||
|
|
.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`
|