移动端设计系统落地: RN+H5 组件库与 Sketch 插件
在汽车之家二手车事业部做了近 3 年移动端工程化,最绕的问题不是某个页面,而是 RN App 和 H5 两端的 UI 不一致——同一个按钮,App 里一个样,H5 里又一个样,设计师改一次,两端各改一遍,联调扯皮。这篇记一下我们怎么用设计系统把这事一次性治住。
一、问题根子: 设计令牌没统一
UI 不一致不是设计师不认真,是令牌没沉淀。颜色、间距、圆角、字号散落在各端代码和各份设计稿里,改一处找不到全貌,自然越改越散。
解决思路三步走:先把令牌集中,再让 RN 和 H5 都从同一份令牌生成样式,最后让设计稿和代码令牌同步。闭环了,一致性才守得住。
二、Style Dictionary: 一份令牌,两端产物
Style Dictionary 把令牌(JSON)编译成各端产物。我们定义一份 token 源:
// tokens/color.json
{
"color": {
"brand": { "value": "#175e88", "type": "color" },
"primary": { "value": "{color.brand.value}", "type": "color" },
"text": { "value": "#202832", "type": "color" },
"muted": { "value": "#596571", "type": "color" }
},
"size": {
"spacing": { "value": "4", "type": "dimension" },
"radius": { "value": "8", "type": "dimension" }
}
}
配置两套输出:
// style-dictionary.config.js
export default {
source: ['tokens/**/*.json'],
platforms: {
rn: {
transformGroup: 'js',
buildPath: 'packages/rn-tokens/',
files: [{ destination: 'tokens.ts', format: 'javascript/module' }]
},
web: {
transformGroup: 'css',
buildPath: 'packages/h5-tokens/',
files: [{ destination: 'tokens.css', format: 'css/variables' }]
}
}
};
一条命令 style-dictionary build,RN 拿到 tokens.ts,H5 拿到 tokens.css,两边引用的都是同一份令牌的派生产物。设计师改色,只改 token 源,两端重新构建,自动同步。
三、RN + H5 双实现组件库
令牌统一后,搭组件库。每个组件有 RN 和 H5 两个实现,但 API 一致:
// Button 组件,双端 API 一致
interface ButtonProps {
variant: 'primary' | 'ghost';
size: 'sm' | 'md';
onPress?: () => void;
label: string;
}
// RN 实现
import { tokens } from '@autohome/rn-tokens';
export const Button: React.FC<ButtonProps> = ({ variant, size, label, onPress }) => (
<TouchableOpacity style={[styles.base, styles[variant], styles[size]]} onPress={onPress}>
<Text style={styles.label}>{label}</Text>
</TouchableOpacity>
);
const styles = StyleSheet.create({
base: { borderRadius: tokens.size.radius, backgroundColor: tokens.color.primary }
});
// H5 实现
import '@autohome/h5-tokens/tokens.css';
export const Button: React.FC<ButtonProps> = ({ variant, size, label, onPress }) => (
<button className={`btn btn--${variant} btn--${size}`} onClick={onPress}>{label}</button>
);
业务调用 import { Button } from '@autohome/ui',构建时按端解析到对应实现。令牌从 tokens.ts / tokens.css 读,样式自动对齐。API 一致是关键——业务代码不用关心端,只换实现。
四、Sketch 插件: 设计稿和令牌双向同步
光统一代码令牌还不够,设计稿要是另搞一套,还是脱节。我们开发了一个 macOS Sketch 插件,做两件事:
- 抽取:扫描 Sketch 文档里的共享样式(颜色 / 字号 / 间距),生成 token JSON,直接喂给 Style Dictionary
- 生成:从 Sketch 符号生成组件骨架代码(RN / H5),设计师新建符号,插件吐出对应组件文件
设计师在 Sketch 里调色,插件把色值写进 token 源,Style Dictionary 重新构建,两端代码自动更新。设计稿改 → 令牌改 → 代码改,闭环了,不用人肉同步。
五、结果与取舍
上线后量化的结果:
| 指标 | 改善 |
|---|---|
| 页面开发时间 | -30% |
| 设计-开发联调时间 | -50% |
| 组件体系推广 | 3+ 业务团队 |
代价是前期搭令牌 + 组件库 + Sketch 插件投入大,小团队不划算。但只要跨 2 个端以上、3 个以上团队复用,设计系统就回本。我们这套后来推广到 3 个以上业务团队,收益是持续的——一次性投入,长期分摊。
小结
多端 UI 不一致的根子是令牌没统一。Style Dictionary 统一令牌派生,双实现组件库统一 API,Sketch 插件打通设计稿和代码。三件套落地后,设计师改一处,两端代码自动同步,联调成本砍半。这是”工程化”这个词真正能落地的样子——不是喊口号,是令牌到代码的链路打通。