PAYATHON 2026

Design Systems 和 Component-Driven Development 如何缓解 UI 开发摩擦?

技术老齐

现代 Design Systems 和 Component-Driven Development 能减少 UI 开发中的重复工作。它们把常用的视觉规则、交互行为和实现细节集中到共享基础设施中,让业务开发者更多地通过组件契约、状态模型和测试来构建界面。

工程师因此不必各自处理所有设计判断,但仍需根据使用场景决定如何组织用户任务、先呈现哪些信息,以及操作失败后如何恢复。把“实现 UI”笼统归结为艺术性思维,已不足以指导工程实践;组件库能承担的用户体验工作也有边界。

先区分技术标准与工程方法

这些方案分属不同层次,不能统称为“行业标准”。

层次可依据的规范或方法主要作用
无障碍要求WCAG提供可验证的可访问性要求
控件交互WAI-ARIA、ARIA Authoring Practices Guide(APG)定义语义,并指导键盘操作、焦点管理等行为
设计数据交换Design Tokens Community Group(DTCG)规范统一 token 的表达与交换格式
开发组织方式Component-Driven Development、设计系统治理组织组件实现、文档、复用和验证

WCAG 和 WAI-ARIA 是 W3C 技术标准,APG 是指导性资料。APG 官方说明明确区分了两者。DTCG 规范属于社区组规范,不在 W3C 标准轨道内,不能称为 W3C Recommendation,详见 DTCG FAQ。

项目可以据此制定自己的工程约束,无需寻找一套覆盖所有 UI 工作的统一标准。

认知负担如何重新分配

设计 token 减少局部选择

如果每个页面都由开发者自行决定字号、间距、颜色和圆角,即使单次选择合理,组合起来也容易失去一致性。

设计系统可以分层管理这些决定:

  • 基础 token 保存颜色、尺寸等原始值。
  • 语义 token 表达用途,例如 color.text.secondary、color.action.primary。
  • 组件内部将语义 token 映射到具体样式。

业务开发者选择“次要文字”时,就不必重新判断该用哪一种灰色。切换主题时,也可以集中调整映射,减少逐页修改。

Style Dictionary支持将平台无关的 token 数据转换为不同平台需要的形式。工具负责转换,团队仍需确定 token 的命名、用途和适用范围。

重复决策集中维护后,可以通过接口复用。设计系统维护者承担了更多前期工作,页面开发者需要记住的细节则随之减少。

组件契约封装重复的交互知识

一个可复用的对话框需要处理关闭操作、焦点进入与返回、键盘导航、可访问名称等问题。基础组件封装这些行为后,使用者就能集中编写业务逻辑:何时打开、显示什么,以及确认后发生什么。

不同工具提供的能力也有区别:

工具主要提供什么仍需开发者处理什么
Tailwind CSS用 utility classes 表达样式,并支持预设尺度布局选择、语义和交互行为
Radix Primitives通用交互原语,处理许多键盘、焦点与 ARIA 细节产品样式、业务流程和正确组合
shadcn/ui可纳入项目并修改的组件源码及默认样式本地修改、升级和组件一致性的维护
Web Components自定义元素等浏览器组件机制组件自身的设计、行为和无障碍实现

具体可参阅 Tailwind 文档、Radix 无障碍说明、shadcn/ui 文档和 HTML Custom Elements 标准。

Component-Driven Development 是一种开发方式,需要团队把组件作为独立单元开发,定义其输入、事件和可观察状态,再将组件组合成页面。采用上述工具,并不会自动建立这套工作方式。

显式状态让 UI 更容易推理

后端工程师熟悉的状态建模同样适用于界面。例如,同时使用 isLoading、isSuccess、hasError,就需要额外约束它们的组合;使用互斥的 idle | saving | saved | error,则可以直接表达哪些状态合法。

React 的状态结构指南也建议避免矛盾、冗余和重复状态。这种建模不依赖 React。对于复杂流程,还可以使用有限状态机或状态图,明确事件、转换条件和副作用。

在 Storybook 中,每个重要状态都可以有独立查看的实例,方便开发者查看超时、权限不足或空数据时的界面,省去反复启动完整业务流程的步骤。Storybook 将 story 定义为组件某个渲染状态的描述。

一套可执行的工作流程

1. 先定义用户任务和状态,再拆组件

以“修改收货地址”为例,先确认:

  • 用户需要哪些信息才能完成修改?
  • 校验失败时保留哪些输入?
  • 保存超时后,用户如何判断是否成功?
  • 用户没有权限时,页面提供什么说明?

再据此确定页面模式和组件边界。直接按照数据库表或接口字段生成表单,容易把存储结构带进用户操作流程。

选择设计系统作为参考时,也要看它是否提供任务模式,以及如何使用按钮等组件。GOV.UK Design System 的 Patterns围绕具体用户任务和页面类型提供指导,说明如何组合组件,并根据使用场景调整。

2. 建立稳定的实现边界

可以采用这样的分层:

Token 与主题
    ↓
基础交互组件
    ↓
业务模式组件
    ↓
页面与用户流程

API 数据 → 适配层/状态模型 → 页面与业务组件

例如,适配层把接口数据和错误转换为页面需要的状态,地址编辑组件处理字段、校验提示和保存反馈。标签关联、焦点样式等通用能力则由基础输入框负责。

这样的分工便于独立验证组件,也能避免接口字段的变化直接影响所有 UI 细节。

3. 把约定变成工具链约束

项目可以逐步引入以下规则:

  • 用 TypeScript 限定组件变体和互斥状态。
  • 通过 ESLint 导入规则,让业务代码优先使用公共 UI 包。
  • 用 Stylelint 或自定义检查限制公共组件中的任意颜色、间距值。
  • 要求公共组件变更附带相应的 story、评审和迁移说明。

制定约束时,也要明确如何扩展。出现新需求后,开发者应能提出新变体或新模式。缺少这条路径,开发者可能会不断绕过公共组件,设计系统也就增加了开发阻力。

4. 用多种验证覆盖不同问题

验证方式适合发现的问题
类型检查非法属性组合、数据结构不匹配
组件交互测试点击、输入、键盘操作和状态变化错误
视觉回归测试间距、换行、主题等外观变化
自动无障碍检查与人工检查部分语义问题,以及键盘、焦点和辅助技术使用问题
完整流程验证与用户观察组件组合后的流程问题、任务理解困难

Storybook 的测试体系支持围绕组件状态组织多种检查。评估测试结果时,需要明确每项检查能说明什么:截图一致只能说明外观没有出现预期之外的变化,无法证明任务流程合理。

代码示例:把状态和视觉规则收进组件

这个 React 和 TypeScript 保存操作组件由调用方控制。调用方处理请求,组件接收状态和事件。

type SaveState =
  | { status: "idle" }
  | { status: "saving" }
  | { status: "saved" }
  | { status: "error"; message: string };

type SaveActionProps = {
  state: SaveState;
  onSave: () => void;
};

export function SaveAction({
  state,
  onSave,
}: SaveActionProps) {
  const saving = state.status === "saving";

  const label = saving
    ? "保存中…"
    : state.status === "error"
      ? "重试保存"
      : "保存";

  return (
    <div>
      <button
        type="button"
        className="save-action"
        disabled={saving}
        onClick={onSave}
      >
        {label}
      </button>

      <p role="status">
        {saving && "正在保存"}
        {state.status === "saved" && "已保存"}
      </p>

      <p role="alert">
        {state.status === "error" && state.message}
      </p>
    </div>
  );
}

样式通过语义变量引用设计规则。以下数值仅用于示例,实际项目应使用经过确认的 token 和主题:

:root {
  --color-action-primary: #1d4ed8;
  --color-text-on-action: #ffffff;
  --color-focus-ring: #111827;
  --space-control-block: 0.625rem;
  --space-control-inline: 1rem;
  --radius-control: 0.375rem;
}

.save-action {
  font: inherit;
  color: var(--color-text-on-action);
  background: var(--color-action-primary);
  padding:
    var(--space-control-block)
    var(--space-control-inline);
  border: 0;
  border-radius: var(--radius-control);
}

.save-action:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 3px;
}

.save-action:disabled {
  cursor: wait;
}

组件中的约束包括:

  • message 只存在于错误状态,减少无效数据组合。
  • 调用者通过状态控制反馈,无需分别操作按钮和提示文字。
  • 视觉值集中在主题变量中,业务调用点无需重复选择颜色和间距。
  • 原生 <button> 保留浏览器提供的按钮语义与键盘行为。

调用方仍需正确更新请求状态,并将服务端错误转换为用户能理解的提示。禁用按钮也不能代替服务端对重复请求的处理。这个示例只覆盖组件边界,完整的保存流程还需要处理这些问题。

Figma-to-Code 应如何接入

从设计到代码,可以围绕已有组件建立映射:

  1. 对齐 Figma 组件与代码组件的名称、属性和变体。
  2. 明确 token 的权威来源、同步方向和冲突处理方式。
  3. 让生成或辅助实现优先复用已有组件。
  4. 通过组件预览、测试和代码评审验证结果。

Figma Code Connect连接设计文件中的组件与代码仓库中的实现,有助于确定设计对应哪个组件、需要传哪些属性。完整的业务逻辑仍需另外实现。

评估其他生成工具时,也应检查它是否复用组件、支持内容变化和响应式布局,以及重新生成时如何处理人工修改。静态画面的相似程度不足以判断代码是否适合长期维护。

实施时容易忽略的边界

设计系统需要持续维护。团队要明确组件由谁负责、如何接受新模式,以及何时废弃旧接口。复制组件源码后,如果各处分叉却无人协调,一致性会逐渐消失。

页面组合也需要单独验证。即使组件本身正确,真实内容中的长文本、空数据和权限限制仍可能暴露预览样例没有覆盖的问题,因此应保留少量关键流程的端到端验证。

无障碍评估需要人工参与。WCAG提供可测试要求,但自动工具无法独立判断网站是否满足全部无障碍标准。W3C 明确要求结合人工评估,详见无障碍评估说明。

要判断认知负担是否下降,可以观察开发者完成常见页面时需要多少额外求助、重复样式修复是否减少,以及他们为何绕过公共组件。同时,也要观察用户完成任务时仍卡在哪里。工具文档能解释减负机制,实际效果还需要在项目中验证。

备注:内容仅供参考。