关于 atomic-design
Atomic Design 是一种将用户界面组织为原子、分子、有机体和模板的技能。它指导团队自下而上构建可复用的展示组件,使用设计令牌和组合,而非继承。
主要功能
- 01四层组件层级
- 02自下而上的组件组合
- 03展示组件的职责边界
- 04用设计令牌管理视觉属性
- 05以组合替代继承
适用场景
- 01组织 UI 组件库
- 02从小型元素构建可复用页面布局
- 03分离界面渲染与数据获取及业务逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jwilger/ agent-skills --skill atomic-design安装后在 Claude Code 中输入/atomic-design确认已加载。
详细介绍
原子设计
价值: 简洁与沟通。通过小型、命名明确且可组合的部分来构建 UI,让团队中的每个人都能理解界面,并避免单体组件带来的复杂性。
目的
介绍如何将 UI 组件组织成复杂度递增的层级:原子、分子、有机体和模板。每个层级都有明确的职责和组合规则。最终形成一个组件系统,其中的每个部分都可复用、可单独测试,并采用团队共用的词汇命名。
实践
由下而上构建四个层级
从最小的可复用元素开始,逐层向上组合。不要跳过任何层级。
四个层级:
-
**原子:**不可再分的 UI 元素。按钮、输入框、标签、图标。一个视觉元素,一项职责。原子的所有视觉属性(颜色、间距、字体排版)都引用设计令牌。
-
**分子:**作为一个整体发挥作用的小型原子组。表单字段(标签 + 输入框 + 错误消息)。搜索栏(输入框 + 按钮 + 图标)。每个分子对应一种交互模式。
-
**有机体:**由分子和原子组成、构成界面中独立区域的复杂组件。导航页眉、完整表单、数据表格。每个有机体对应一个功能区域。
-
**模板:**页面级布局,将有机体排列成完整视图。仪表板模板、列表详情模板。模板定义结构和内容槽位,不定义具体数据。
示例:
Atom: Button, Input, Label, ErrorMessage
Molecule: FormField (Label + Input + ErrorMessage)
Organism: LoginForm (FormField + FormField + Button)
Template: AuthPage (Header + LoginForm + Footer)
应该:
- 构建新 UI 时,从原子开始
- 根据组件的本质命名,而不是根据它显示的数据命名
- 将原子控制在 50 行以内,分子控制在 100 行以内
不应该:
- 直接用原始标记构建有机体——先提取原子
- 创建不组合系统中原子的分子
- 在有机体尚未创建时就直接构建模板
保持组件仅负责呈现
组件负责渲染 UI。它们通过 props 接收数据。它们不获取数据、不管理业务逻辑,也不持有应用状态。
- 通过 props 或等效方式传递所有数据
- 为用户操作发出事件——不要处理副作用
- 将数据容器与呈现组件分开
示例:
Presentational (good):
UserCard({ name, email, avatar }) -> renders UI
Container (separate):
UserCardContainer() -> fetches data, passes to UserCard
不应该:
- 在原子、分子或有机体中发起 API 调用
- 将组件与特定数据源耦合
- 在同一个组件中混合渲染逻辑与业务逻辑
所有视觉属性都使用设计令牌
将每项设计决策(颜色、间距、字体排版、阴影、圆角)提取为命名令牌。组件引用令牌,绝不使用原始值。
- 创建新设计系统时,第一步就定义令牌
- 组件中的每种颜色、间距值和字号都必须来自令牌
- 更改令牌会更新所有引用它的组件
示例:
/* Tokens */
--color-primary: #0066cc;
--spacing-sm: 8px;
--spacing-md: 16px;
/* Component uses tokens, not values */
.button { background: var(--color-primary); padding: var(--spacing-sm); }
不应该:
- 在任何组件中硬编码
#0066cc或8px - 为单个组件创建一次性令牌名称
- 定义从未使用的令牌(令牌应当发挥作用)
组合,不要继承
通过嵌套更简单的组件来构建复杂组件。不要通过类继承或层层传递 props 来扩展基础组件。
- 通过传递 children 或槽位来组合布局
- 保持组件树扁平——优先使用同级组件,而不是深层嵌套
- 需要变体时,用原子组合出新的分子,而不是给现有分子添加标记
应该:
IconButton = Icon + Button(组合)Card > CardHeader + CardBody(槽位)
不应该:
FancyButton extends Button(继承)- 用一个包含 15 个变体 props 的 Button 组件
执行说明
在所有模式下均为建议。组件层级与令牌规范由开发者自行执行。
硬性约束:
- 仅引用令牌(组件中不得使用原始值):
[RP]
约束
- “绝不跳过层级”:实际上属于分子(由多个视觉元素组成)的原子,即使你把它命名为“原子”,也跳过了层级。分类依据是组件的实际属性,而不是它所在的目录。如果你的“原子”包含 3 个带布局逻辑的内部元素,它就是一个分子。
- “不使用原始值”:为每个唯一值定义一个令牌,却从不复用这些令牌,这就失去了令牌的意义。令牌的作用是复用并保持一致性。如果某个令牌只使用了一次,请自问:这个值是否应该与其他组件共享?如果是,令牌定义正确。如果不是,这个值可能应该来自更通用的令牌(例如,使用
spacing-md,而不是card-header-padding-top)。 - 展示层边界:展示层意味着:通过 props 传入数据,通过回调向外发送事件。筛选要展示的数据属于展示层(这是视图层关注的事项)。获取数据、修改状态或调用 API 则不属于展示层。判断标准:使用模拟 props 的 Storybook 故事能否让这个组件呈现完全相同的效果?如果它需要运行中的后端,就不属于展示层。
验证
按照此技能的指导完成工作后,请验证:
- 每个 UI 元素都能追溯到一个原子(organism/template 中没有原始标记)
- 已定义设计令牌,且组件引用了这些令牌(没有硬编码值)
- 每个组件都承担与其层级相符的单一职责
- 组件属于展示层(传入数据,向外发送事件)
- 层级已记录,或能从目录结构中明确看出
如果任何一项不符合,请在继续之前重新检查相关实践。
依赖项
此技能可独立使用。如需增强工作流,可与以下内容集成:
- design-system: 设计系统规范提供此技能将在代码中实现的令牌定义、组件目录和层级。
- domain-modeling: 来自领域模型的读取模型定义组件通过 props 接收的数据。
- tdd: 在每个层级单独测试组件——原子测试、分子测试、organism 测试。
- event-modeling: 事件建模会话中的线框图可确定需要哪些组件。
缺少依赖项?使用以下命令安装:
npx skills add jwilger/agent-skills --skill tdd