mcpField
R
repeated-component-alignment

repeated-component-alignment

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

关于 repeated-component-alignment

Repeated Component Alignment 是面向界面开发者的设计技能,适用于卡片、行和信息块等重复元素。它介绍基于固定槽位的布局方法,使内容长度变化时仍保持对齐,并确保可查看被截断的文本。

主要功能

  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 repeated-component-alignment

安装后在 Claude Code 中输入/repeated-component-alignment确认已加载。

详细介绍

重复组件对齐

当一个组件被反复渲染时——无论是卡片网格、列表、表格、导航菜单、一排 KPI 磁贴还是信息流——它就不再是单个盒子,而会成为一种模式。模式的价值在于节奏:眼睛只需学习一次布局,就能在每个实例中扫描同一个位置(标题行、价格行、操作行)。除非组件经过设计,能够吸收内容长度的差异,否则内容长度的变化就会打乱这种节奏。

这个原则具有普遍性。卡片是最常见的情况,但同样的规则也适用于列表行、表格单元格、导航项、磁贴、评论条目、仪表盘组件、搜索结果——任何重复出现的内容。把它们都视为固定槽位模型,而不是自由格式的容器。

目标:**无论内容长度如何,各个实例的外观都保持一致。**这既涉及内容制作(按目标长度撰写),也涉及布局工程(构建能够容纳差异的槽位)。本指南讲解布局这一部分,以及两者的交汇之处。


槽位模型

为槽位统一命名,并将其视为每个实例都必须遵守的约定。以下以产品卡片为例:

┌──────────────────────┐
│ [media]              │  ← fixed aspect ratio
│                      │
├──────────────────────┤
│ ● Badge              │  ← optional slot, space reserved
│ Title                │  ← clamp to N lines
│ Subtitle / meta      │
│                      │
│ Description text…    │  ← flexible slot, grows
│                      │
├──────────────────────┤
│ €19.99      Read more│  ← anchor, pinned to bottom
└──────────────────────┘

同样的三条规则也适用于列表行(头像 · 姓名 · 元信息 · 状态固定在右侧)、KPI 磁贴(标签 · 大号数字 · 趋势固定在底部)或搜索结果(标题 · URL · 截断的摘要):

  • 每个槽位的位置都是固定的,无论某个实例是否包含该槽位的内容。
  • 由一个槽位吸收差异(通常是描述或摘要)。其他槽位都固定或截断。
  • 锚定元素固定在指定位置——主要操作或数值(CTA、价格、状态、趋势)在每个实例中的位置都相同,不受其上方或旁边内容多少的影响。

根据状态切换的控件

一个单元格可能会根据状态显示不同的控件——先是按钮,然后是输入框,再变成数值或链接——但它仍然是一个槽位。为每个位置设定固定宽度,并让其中的控件拉伸以填满该位置。每一行、每种状态下的同一位置都承担相同的作用。按内容调整尺寸的控件会随着标签改变宽度,导致行重新排布、相邻控件在光标下方移动,整列也不再像一组列表。

对齐锚点

最常见的问题是:文本长度不同,导致锚定元素(例如“阅读更多”链接、价格或状态标签)在每个实例中的位置不一致。解决方法是让可伸缩槽位扩展,并将锚点推到固定边缘。

纵向布局(卡片、磁贴)——将页脚固定在底部:

.item {
  display: flex;
  flex-direction: column;
  height: 100%;            /* fill the grid/flex track */
}

.item__media {
  aspect-ratio: 4 / 3;     /* never let media height vary */
  object-fit: cover;
}

.item__description {
  flex: 1;                 /* the flexible slot absorbs the slack */
}

.item__footer {
  margin-top: auto;        /* pin the anchor (price + CTA) to the bottom */
}

要让同级实例高度相等,容器轨道必须拉伸它们——CSS Grid 和 Flex 默认会这样做(align-items: stretch)。然后,height: 100% 会让每个实例填满其轨道,而 margin-top: auto 会将所有页脚对齐。

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-4);
  /* align-items: stretch is the default — do not override it */
}

横向布局(列表行、表格单元格)——将锚点固定在右侧:

.row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.row__title {
  flex: 1;                 /* title absorbs the width variance */
  min-width: 0;            /* REQUIRED for the title to be allowed to shrink/ellipsis */
}
.row__status {
  margin-left: auto;       /* status pinned to the right edge */
}

不要用硬编码的 height 强制统一尺寸——由自然高度最大的实例决定整体尺寸,超出的内容会被裁切或溢出。让轨道拉伸,并固定锚点位置。


为可选槽位预留空间

某个槽位只在部分实例中出现——例如徽章、折扣标签或“已验证”标记——会导致有该槽位的实例中,其后的所有内容发生偏移,从而破坏对齐。有两种修复方法:

  1. 预留槽位——始终以固定尺寸渲染容器;没有内容时也保留空容器:
.item__badge-row {
  min-height: 24px;        /* always occupies the row */
}
  1. 叠加槽位——使用绝对定位,使其不参与文档流:
.item__badge {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
}

当元素是行内元信息时,预留槽位;当元素是媒体上的标记(促销、新品)时,使用叠加。无论采用哪种方式,其后方的槽位都必须在每个实例中从相同位置开始。


限制溢出文本——并让用户能查看完整内容

当某个区域必须保持固定尺寸、但内容长度不一时,可将文本限制为指定行数,并用省略号标示截断位置。这样可以保持布局稳定。但截断会隐藏信息——务必确保用户能查看完整内容。

多行文本——限制为 N 行:

.clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

单行值(名称、SKU、路径)——使用省略号:

.truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;            /* needed inside a flex row to allow shrinking */
}

提供查看完整内容的方式。 如果无法查看完整文本,截断或省略后的字符串就会成为易用性陷阱。请提供以下方式:

  • 原生工具提示,用于纯文本:<span title="Full value here">…</span>。零成本,随处可用,但仅支持悬停(不支持触屏),且无法设置样式。
  • 自定义工具提示,适用于需要支持触屏、设置样式或展示富内容的场景。
  • 原地展开,适用于完整内容本身就是重点的场景——使用“阅读更多”切换按钮展开当前内容,或打开详情视图,而不是永久隐藏用户需要的文本。

只有在文本确实被截断时才添加工具提示——对完整显示的字符串设置 title 会产生多余的悬停提示。检测溢出(scrollWidth > clientWidth),并有条件地设置 title。

动态生成的列表最容易忽略这一点。 导航栏、目录、树形视图或侧边栏会将来自数据的标签渲染到固定宽度的列中,因此总会有一些行被截断。为每一行的完整标签设置 title(这是“有条件地设置”的例外:列表很长、宽度固定,而且逐行检测溢出的成本高于多余的悬停提示)。先解码文本——根据渲染后的 HTML 构建 title 会让 &amp; 和 &quot; 原样显示出来,观感比截断更差。

处理长度不定内容的优先顺序:

  1. 控制内容长度——最简洁的解决方法。为内容作者设定目标长度(例如标题不超过 60 个字符,摘要不超过 120 个字符),这样大多数值就不需要截断。布局技巧是安全网,而非首选方案。
  2. 限制长度并提供查看完整内容的方式——适用于无法保证内容长度的情况(用户生成内容、第三方信息流、i18n 文本扩展)。
  3. 让一个区域自由伸展——对于唯一允许长度变化的区域,用 flex 吸收长度变化,并固定其后的所有内容。

区域内的图像

只限制图像的一个维度,绝不要同时限制宽度和高度。设置宽度并使用 height: auto,或指定固定的 aspect-ratio 并使用 object-fit。同时设置两个约束会导致变形。

Grid 会将未包装的图像拉伸至列宽,flex 列则会沿交叉轴拉伸图像。请为图像添加包装元素,或声明 align-self/justify-self。如果同一个徽标在一张卡片中看起来被压扁、在另一张中却正常,几乎总是这个原因。

在将标记错位归咎于 CSS 之前,先检查素材尺寸。文件中自带的内边距会导致图案偏离边框中心,任何布局规则都无法修正这一点。

标签和值列表

重复的标签/值列表应为标签列设置固定宽度:可以使用首列固定的 Grid,也可以使用表格。这样每个值都会从同一位置开始。带间距并使用分隔符号(箭头、短横线、竖线)的 flex 行无法实现对齐,而且每行都多出一个需要读者扫过的符号。


国际化说明

翻译后的文本通常会变长——德语和芬兰语的文本通常比英语长 30–40%。在英语中对齐完美的组件,在其他语言环境中可能会错乱。设计时要考虑较长的情况:限制文本长度,为可选区域预留空间,为 flex 行设置 min-width: 0,绝不要因为某个标签在源语言中能显示为一行,就假设它在其他语言中也能。

控件区域在不同状态下保持同一高度

当画布与控件争夺纵向空间时,只显示当前状态下可用的控件;其他控件则在其他状态下占据相同位置。相反,显示或隐藏控件行会使画布在每次状态变化时调整大小,产生故障感,并移动用户正在查看的内容。处于某种状态时被禁用的控件应最先让出空间。


审查清单

  • 重复组件是否采用已定义的插槽模型——每个实例都以相同顺序填充相同插槽?
  • 同级实例是否通过拉伸网格或弹性布局轨道保持等高,而非使用硬编码高度?
  • 锚点(CTA/价格/状态/数值)是否固定——列布局使用 margin-top: auto,行布局使用 margin-left: auto——以便在各实例间对齐?
  • 是否只有一个插槽吸收长度差异,其余插槽固定或限制长度?
  • 可选插槽(徽标、标签)是否预留空间或采用覆盖方式,以免推移后续插槽?
  • 媒体是否使用固定的 aspect-ratio,确保尺寸始终不变?
  • 每张图片是否只在一个维度上受限,并且不会被网格或弹性布局拉伸?
  • 标签/数值列表是否使用固定宽度的标签列,而非使用带分隔符的弹性行?
  • 多行插槽是否限制行数,单行数值是否使用省略号?
  • 会截断文本的弹性行是否设置了 min-width: 0,以允许文本收缩?
  • 文本被截断时,是否都能通过标题/工具提示/展开查看完整内容?
  • 是否仅在文本实际溢出时才显示工具提示?
  • 内容编写者是否明确目标长度,使截断成为安全措施而非常态?
  • 是否根据译文最长的语言检查过插槽,而不只是根据源语言?
  • 单元格根据状态切换控件时,每种状态是否都填充相同的固定宽度插槽?
  • 控件区域在每种状态下是否保持相同高度,且特定状态的控件是否共用插槽?

评论

支持 Markdown