mcpField
S
surface-separation

surface-separation

github.com/dembrandt设计与 UI174226 次安装1 周前更新
代码仓库

关于 surface-separation

surface-separation 是面向设计师和开发者的 UI 设计技能,帮助确定卡片、面板等界面表面的区分方式。它说明边框、层级阴影和填充色的适用场景,并提供透明度、颜色令牌及嵌套表面的建议。

主要功能

  1. 01选择边框、层级阴影或填充色
  2. 02指导嵌套表面的区分
  3. 03将透明度用于界面状态
  4. 04优先使用颜色令牌而非透明色
  5. 05提供表面区分检查清单

适用场景

  1. 01为卡片和面板选择视觉处理方式
  2. 02检查组件中的透明度与颜色用法
  3. 03减少嵌套界面中过度的视觉区分

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dembrandt/dembrandt-skills --skill surface-separation

安装后在 Claude Code 中输入/surface-separation确认已加载。

详细介绍

表面分离

表面——卡片、面板、工具栏、行——需要与其背后的内容清晰区分。实现这一点恰好有三种方式,而常见错误几乎总是三种方式都用足强度,而不是在它们之间选错。

每个表面只选一种策略

策略机制给人的感觉最适合用于
边框边界处的 1px 线条精确、描绘感、文档式密集型 UI、表格、表单,以及边缘本身具有意义的任何内容
层级暗示高度的阴影悬浮、临时、位于上方模态框、下拉菜单、弹出框、拖拽状态
填充对比鲜明的背景色调成组、嵌入、属于页面的一部分区块、侧边栏、交替行、行内提示框

每种方式回答的问题各不相同。边框表示表面在哪里结束。层级表示表面高出页面多少。填充表示表面属于什么。根据用户实际想知道的问题来选择。

**规则:**不要在同一个表面上同时使用这三种方式。卡片如果同时有明显的边框、投影,以及区别于页面的背景色调,就等于把边界强调了三次。结果是什么都没突出,因为所有地方都在强调。这是导致 UI 被人形容为“杂乱”或“厚重”却说不出原因的最常见单一原因。

合理搭配

在一种特定情况下,边框和层级搭配使用是正确的:浅色页面上的浅色表面,此时单靠微妙的阴影会变得不明显,边缘也会模糊。这里由边框界定边界,阴影提供深度——两者各司其职。有关阴影比例以及与之搭配的边框色调,请参阅 [[elevation-and-depth]]。

要将信号控制在两种,表面填充色需保持与页面色调相同或接近。一旦背景色也明显偏离页面色调,就等于第三次强调边缘。

嵌套

表面中的表面应改变策略,而不是加强同一种策略。有边框的卡片内再放有边框的行,会形成一片缺乏层级的线条网格。内层行可以改用不同的填充色,或去掉内层边框并依靠间距——关于何时仅靠接近程度就足以形成分组,请参阅 [[gestalt-ui-organisation]]。

真正的限制是嵌套深度。超过两层可见分隔后,任何策略都难以清晰呈现。应改为扁平化结构。

不透明度表示状态,而非色调

不透明度传达的是某个元素暂时无法完全使用:已禁用、正在加载、等待中、正在拖拽。这就是它在 UI 中的全部用途。

.btn:disabled     { opacity: 0.4; }
.card.is-loading  { opacity: 0.7; }
.row.is-dragging  { opacity: 0.5; }

仅将其用于此目的,才能让信号清晰易懂。若因其他原因使用不透明度,这个信号就失去了意义。

切勿用透明度着色

用 rgba(brand, 0.1) 或 opacity: 0.6 来生成较浅的颜色,是一种反模式。应将色调定义为真正的令牌:

/* Wrong — the rendered colour depends on whatever is behind it */
.badge { background: rgba(37, 99, 235, 0.12); }

/* Right — a resolved token with a known value */
.badge { background: var(--color-brand-50); }

使用透明版本会导致三方面的问题:

  1. **颜色无法确定。**颜色会与背后的内容混合,因此会随父级、主题和滚动位置而变化。同一组件的两个实例会呈现不同的颜色。
  2. **无法验证对比度。**WCAG 比率是在两种具体颜色之间计算的。半透明图层在合成之前没有具体颜色,因此任何自动化检查都无法确认其上的文字是否清晰易读——它在一种环境中可能通过,在另一种环境中却会失败。
  3. **设计系统会失去这个值。**只以 alpha 乘数形式存在的色调不是令牌,无法被引用、导出、进行版本管理,也无法按主题替换。

根据品牌色通过算法生成色调,并将其存储为令牌——[[algorithmic-color-palette]] 介绍了如何根据一种或两种源颜色生成完整色阶。

叠加半透明效果

当一个半透明元素叠加在另一个半透明元素上时,问题会进一步加剧。每一层都会与上一层叠加,因此最终渲染出的颜色取决于其下方的整条层级链——而编写组件时,没有人知道这条链是什么。

切勿在 background-color 已带有 alpha 通道的元素上设置 opacity。 如果同一组件中两者同时出现,就说明其中一个用错了:要么背景应使用不透明的设计令牌,要么应将透明度用于表达状态,并确保背景不透明。

玻璃和磨砂效果是有意为之的例外,因为不可预测的背景正是其设计目的。但这也有代价:其上的文本需要单独的不透明底色,或者需要能在最差情况下的背景上仍保证对比度。不要让玻璃表面承载正文,却不提供其中任何一项。

禁用状态是例外,也恰好印证了规则

禁用元素不受 WCAG 对比度最低要求的约束,这也正是低透明度只适用于此处、而不适用于其他地方的原因——这是唯一一种以刻意降低可读性来传达预期信息的情况。仅靠透明度仍不足以表达禁用状态:还应配合 cursor: not-allowed 和不可交互状态。[[button-states]] 中列出了完整的状态矩阵。

检查清单

  • 每个表面是否只采用一种区分策略,或者采用边框/阴影与页面色调填充的组合?
  • 是否有表面同时使用边框、阴影和不同的填充色?
  • 嵌套层级的区分方式是否有所变化,而非重复使用同一策略,并且不超过两层?
  • 代码库中的每个 opacity 值是否都用于表达某种状态——禁用、加载或拖动?
  • 所有色调是否都使用真正的设计令牌,而非 alpha 倍数?
  • 是否有组件在已半透明的背景上又设置了 opacity?
  • 玻璃表面上的文本是否有不透明底色,或者有最差情况下仍能保证对比度的方案?

评论

支持 Markdown