你的设计系统存在耦合问题
Source: Dev.to
要为您提供翻译,我需要您粘贴或提供要翻译的文章正文内容。请将文章的文本(除代码块和 URL 之外)贴在这里,我会按照要求将其翻译成简体中文并保持原有的格式。
介绍
我直言不讳,珍惜你的时间——少废话,多价值。
挑选一个流行的组件库,找到 Button 组件。你会看到:
- 结构 – 带有 ARIA 属性的语义化 HTML(可访问性契约)。
- 交互 – JavaScript 处理焦点、键盘事件、展开状态、滚动锁定等。
- 美观 – 颜色值、间距、字体大小、边框半径、悬停过渡以及变体(xl、lg、md、primary、secondary,……)。
一个组件承担了三项工作。
三大支柱
| 支柱 | 关注点 | 示例 |
|---|---|---|
| 结构 | 语义化 HTML、ARIA 角色、可访问性契约 | 它是什么元素?它的 ARIA 角色是什么? |
| 交互 | 行为逻辑、焦点管理、键盘导航、滚动锁定 | 键盘快捷键、模态打开/关闭 |
| 美观 | 视觉处理——颜色、间距、排版、边框半径、层次 | 品牌配色、悬停状态 |
这些支柱在任何产品中都会不断变化。更新配色方案(美观)、添加新表单字段(结构)或引入键盘快捷键(交互)都可能迅速成为交织的 UI/UX 的温床。
设计令牌
设计令牌 是用于存储视觉决策的命名变量。与其在组件中硬编码 #2563eb,不如引用 --color-primary。与其写死 16px,不如引用 --space-md。数值只在一个位置定义,其他所有地方都指向它。
/* Example token definitions */
:root {
--color-primary: #2563eb;
--space-md: 1rem;
--radius-sm: 4px;
}我的论点
解耦。就是这样。
组件 vs. 令牌
- 组件 拥有 结构 和 交互。
- 令牌 拥有 美学。
具体示例
// Button component (structure & interaction only)
function Button({ onClick, children }) {
return (
<button onClick={onClick}>
{children}
</button>
);
}/* Token system – aesthetics */
:root {
--color-primary: #2563eb;
--button-bg: var(--color-primary);
--button-padding: var(--space-md);
--button-radius: var(--radius-sm);
}
/* Component hook */
.button {
background: var(--button-bg);
padding: var(--button-padding);
border-radius: var(--button-radius);
}三层(原始 HTML、:root 变量、CSS 映射)→ 零耦合。
此修复内容
主题更改
编辑单个令牌:
/* Before */
--color-primary: #2563eb;
/* After */
--color-primary: #dc2626;使用 --color-action-primary 的所有组件会自动更新——无需触碰组件文件,也无需重新部署 JavaScript。
品牌刷新
在令牌文件中更改一个键/值对,整个 UI 即可即时反映新的品牌。
那么,为什么不使用 CSS‑in‑JS?
CSS‑in‑JS 解决了特异性冲突、命名冲突和死代码问题,但它引入了一种新的耦合:视觉处理成为组件树的一部分。要覆盖它需要了解包装器;要进行主题化需要了解主题结构;要进行测试需要模拟运行时值。我们把全局 CSS 的问题换成了组件耦合——仍然是一团乱,只是换到了另一个文件中。
Tailwind?
Tailwind 移除了对 JavaScript 的耦合,这是进步。然而,像下面这样的实用类字符串仍然把美学与结构纠缠在一起:
<button class="bg-primary text-white py-2 px-4 rounded">
Click me
</button>主题化意味着在每个组件中进行查找‑替换;暗黑模式需要在每个类前加 dark:;品牌刷新会影响每个文件。
Tailwind 是实用优先的。这里描述的方法是 token‑first:视觉决策存在于一个独立的 token 层,而不是写在标记中。
分离
| 关注点 | 拥有 | 不涉及 |
|---|---|---|
| 结构 | HTML 元素、ARIA 角色、语义约定 | 颜色、间距、JS 行为 |
| 交互 | 焦点、键盘导航、展开、滚动锁定 | 标记选择、视觉处理 |
| 美学 | 令牌 → CSS 自定义属性 → 组件钩子 | DOM 结构、事件处理 |
没有重叠——更改一列,其他列保持不受影响。
结论
这并非理论,而是构建 UI 系统的实用方法。停止将本应位于不同层的关注点捆绑在一起。