首页
/ impeccable 生产级加固实战:用 /harden 全面处理错误态、国际化、文本溢出与边界场景

impeccable 生产级加固实战:用 /harden 全面处理错误态、国际化、文本溢出与边界场景

2026-09-07 11:56:57作者:郜逊炳

导读

本文围绕设计语言项目 Impeccable 中 /harden 命令的完整规范(reference/harden.md)展开,讲解如何把一个"只对完美数据生效"的前端界面,加固成能应对真实用户极端输入、网络故障、多语言与多脚本环境的生产级界面。读完你将掌握:加固前的风险盘点方法、七个核心加固维度的可落地实现(文本溢出、i18n、错误处理、边界条件、输入校验、可访问性与性能韧性)、配套的手动与自动化测试策略,以及该规范在 Impeccable 技能仓库中的源码级定位与用法。

一、/harden 在 Impeccable 命令体系中的定位

Impeccable 将设计工作组织为一组面向 AI 编码 Agent 的子命令,每个命令对应一份独立规范文档,统一登记在 SKILL.md 的 Commands 表中:

命令 类别 描述
harden [target] Refine 生产就绪:错误处理、i18n、边界场景(见 reference/harden.md
polish [target] Refine 上线前的最终质量收尾
audit [target] Evaluate 可访问性、性能、响应式等技术质量检查

机器可读的命令元数据位于 command-metadata.json,其中对 harden 的触发语义描述得比 SKILL.md 更完整:

"Make interfaces production-ready: error handling, i18n, text overflow, edge case management, and resilience under real-world data. Use when the user asks to harden, make production-ready, handle edge cases, add error states, or fix overflow and i18n issues."

也就是说,只要用户请求中出现 "make it production-ready""handle edge cases""add error states""fix overflow""fix i18n issues" 等意图,就该加载 harden 规范并执行加固。参数 [target] 表示可以指定目标文件或路由;仓库 README.md 中给出了一行最直观的调用示例:

/impeccable harden checkout      # Add error handling + edge cases

在命令分类脚本 skill-categories.js 中,hardenpolishoptimizeonboard 同属 harden 类别,且类别顺序 ['create', 'evaluate', 'refine', 'simplify', 'harden', 'system'] 表明它属于偏后期、面向"上线前抗风险"的一组操作;在仓库视觉规范 DESIGN.md 中该类别还有专属的 oklch 颜色令牌 category-harden-bordercategory-harden-text 用于相关检测与界面呈现。

本规范在仓库中有多份同步副本:.hermesskill/plugin/skills/impeccable/ 三处的内容一致(skill/reference/harden.mdplugin/skills/impeccable/reference/harden.md 中交接命令被写为 {{command_prefix}}impeccable polish 占位符形式,安装时会被替换成实际的命令前缀)。下文即按这份规范逐层展开。

二、第一步:先评估加固需求,再动手改

规范开篇就给出立场:只对完美数据生效的设计不算生产就绪。因此加固不是"想起一处补一处",而是先系统性地盘出弱点与边界用例,分为三条测试主线。

1. 用极端输入测试

  • 极长文本:姓名、描述、标题等字段填入超长内容;
  • 极短文本:空字符串、单个字符;
  • 特殊字符:emoji、RTL(从右到左)文本、带重音符号的字母;
  • 大数字:百万、十亿级别的数值;
  • 大量条目:1000+ 列表项、50+ 下拉选项;
  • 无数据:各类空状态(empty states)。

2. 测试错误场景

错误场景 需要验证的行为
网络故障 离线、慢速、请求超时时的界面表现
API 错误 400/401/403/404/500 各状态码的差异化处理
校验错误 表单校验失败提示
权限错误 无权查看/编辑时的呈现
限流 rate limiting 被触发时的提示与重试策略
并发操作 重复提交、竞态条件

3. 测试国际化

  • 长译文(德语通常比英语长 30%)下的布局变化;
  • RTL 语言(阿拉伯语、希伯来语);
  • 字符集:中日韩(CJK)、emoji 等多字节字符;
  • 日期/时间格式差异;
  • 数字格式差异(如 1,0001.000);
  • 货币符号差异。

规范用一行大写强调收束:"CRITICAL: Designs that only work with perfect data aren't production-ready. Harden against reality."——这也是后续所有加固动作的总纲。

三、七个加固维度:系统性提升韧性

规范将加固工作划分为七个维度,逐一给出做法与可复制的代码。以下按维度展开并补充实现层面的说明。

3.1 文本溢出与换行(Text Overflow & Wrapping)

长文本处理有三种互相补充的 CSS 手段:

/* 单行省略号 */
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 多行截断 */
.line-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 允许换行 */
.wrap {
  word-wrap: break-word;
  overflow-wrap: break-word;
  hyphens: auto;
}

Flex/Grid 溢出防护:flex 与 grid 子项默认的最小尺寸会跟随内容,导致溢出容器,需要显式允许收缩:

/* 防止 flex 子项溢出 */
.flex-item {
  min-width: 0; /* 允许收缩到内容尺寸以下 */
  overflow: hidden;
}

/* 防止 grid 子项溢出 */
.grid-item {
  min-width: 0;
  min-height: 0;
}

响应式文本尺寸

  • clamp() 实现流式排版(fluid typography);
  • 设置可读的最小字号:移动端正文以 16px 为底线,只有真正次要的文本才允许 14px。这条"16px 地板"并非 harden 独有——字体与排印规范 reference/typeset.md 明确写着 "Keep body copy comfortably readable and zoomable. Use 1rem / 16px as the ordinary web body floor unless a dense role, platform convention, or user setting justifies otherwise."。harden 特别补充了背后的移动端成因:iOS Safari 会对小于 16px 的聚焦输入框强制放大页面,从而破坏表单布局
  • 测试 200% 缩放下文本缩放;
  • 确保容器随文本扩展而非被文本撑破。

3.2 国际化(i18n)

为译文扩展预留空间

  • 为翻译文本预留 30%–40% 的空间预算;
  • 用能自适应内容的 flexbox/grid;
  • 优先用"通常最长的语言"(一般是德语)做测试;
  • 避免给文本容器写固定宽度。

React/JSX 中"假设短英文"是典型反例:

// ❌ Bad: Assumes short English text
<button className="w-24">Submit</button>

// ✅ Good: Adapts to content
<button className="px-4 py-2">Submit</button>

RTL(从右到左)支持:核心是用逻辑属性(logical properties)替代物理属性,使布局自动跟随书写方向:

/* 使用逻辑属性 */
margin-inline-start: 1rem; /* 而不是 margin-left */
padding-inline: 1rem; /* 而不是 padding-left/right */
border-inline-end: 1px solid; /* 而不是 border-right */

/* 或借助 dir 属性 */
[dir="rtl"] .arrow { transform: scaleX(-1); }

字符集支持:全链路使用 UTF-8 编码;测试中文/日文/韩文(CJK);测试 emoji(单个可达 2–4 字节);覆盖拉丁、西里尔、阿拉伯等不同书写系统。

日期/时间与数字/货币格式化:交给标准化的 Intl API,而不是手写格式:

// ✅ 用 Intl API 做正确的本地化格式
new Intl.DateTimeFormat('en-US').format(date); // 1/15/2024
new Intl.DateTimeFormat('de-DE').format(date); // 15.1.2024

new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(1234.56); // $1,234.56

复数规则(Pluralization):不能用英文式"加不加 s"的假设去处理其他语言的复数,例如俄语、阿拉伯语有多套复数形式。规范的示例:

// ❌ Bad: Assumes English pluralization
`${count} item${count !== 1 ? 's' : ''}`

// ✅ Good: Use proper i18n library
t('items', { count }) // Handles complex plural rules

3.3 错误处理(Error Handling)

网络错误要满足五个要素:给出清晰的错误文案;提供"重试"按钮;说明发生了什么;适用时提供离线模式;覆盖超时场景。可恢复的错误态 UI 是标准做法:

// 带恢复路径的错误态
{error && (
  <ErrorMessage>
    <p>Failed to load data. {error.message}</p>
    <button onClick={retry}>Try again</button>
  </ErrorMessage>
)}

表单校验错误:错误提示内联展示在字段附近;文案清晰具体;给出修正建议;不要无谓地阻断提交;出错时保留用户已输入的内容(不要清空表单)。

API 错误:按状态码做差异化处理,规范给出了一张可直接对照的分诊表:

状态码 处理方式
400 展示具体的校验错误
401 跳转登录
403 展示权限不足错误
404 展示"未找到"状态
429 展示限流提示
500 展示通用错误并引导联系支持

优雅降级(Graceful degradation):核心功能在无 JavaScript 时也能工作;图片必须有 alt 文本;采用渐进增强;为不支持的新特性提供降级方案。

3.4 边界条件与极端场景(Edge Cases & Boundary Conditions)

空状态:覆盖"列表无条目""无搜索结果""无通知""无数据可展示",并给出明确的下一步动作。

加载状态:覆盖首次加载、分页加载、刷新三种时机;用"正在做什么"的措辞(如 "Loading your projects...")而非笼统的 spinner;长操作用时间估算。

大数据集:使用分页或虚拟滚动;提供搜索/过滤能力;做性能优化;绝不一次性加载全部 10000 条。

并发操作:防止重复提交(加载期间禁用提交按钮);处理竞态条件;乐观更新要带回滚;设计冲突解决策略。

权限状态:覆盖无权查看、无权编辑、只读模式,并清楚解释原因。

浏览器兼容:为新特性准备 polyfill;为不支持的新 CSS 提供回退;用特性检测(feature detection)而非浏览器嗅探;在目标浏览器中测试。

3.5 输入验证与净化(Input Validation & Sanitization)

客户端校验:必填字段、格式校验(邮箱、电话、URL)、长度限制、正则 pattern、自定义校验规则。

服务端校验(永远要做):绝不能只信客户端校验;所有输入都要在服务端校验与净化;防御注入攻击;做限流。

约束声明:用原生属性把约束写清楚,并用 aria-describedby 关联提示文案,让约束对屏幕阅读器也可感知:

<!-- 设置清晰的约束 -->
<input
  type="text"
  maxlength="100"
  pattern="[A-Za-z0-9]+"
  required
  aria-describedby="username-hint"
/>
<small id="username-hint">
  Letters and numbers only, up to 100 characters
</small>

3.6 可访问性韧性(Accessibility Resilience)

  • 键盘导航:全部功能可键盘触达;Tab 顺序符合逻辑;模态框内管理焦点;长内容提供跳转链接(skip links)。
  • 屏幕阅读器支持:正确的 ARIA 标签;用 live regions 播报动态内容变化;描述性 alt 文本;优先语义化 HTML。
  • 高对比度模式:在 Windows 高对比度模式下测试;不能只依赖颜色传达信息;提供替代视觉线索。

3.7 性能韧性(Performance Resilience)

慢网速:渐进式图片加载;骨架屏(skeleton screens);乐观 UI 更新;用 Service Worker 提供离线支持。

内存泄漏:组件卸载时清理事件监听、取消订阅、清除定时器/间隔器、abort 未完成的请求。

节流与防抖

// 搜索输入防抖
const debouncedSearch = debounce(handleSearch, 300);

// 滚动处理器节流
const throttledScroll = throttle(handleScroll, 100);

四、测试策略:把加固变成可验证的闭环

手动测试清单

  • 用极端数据测试(极长、极短、空值);
  • 在不同语言下测试;
  • 离线测试;
  • 限速测试(节流到 3G 网速);
  • 用屏幕阅读器测试;
  • 纯键盘操作测试;
  • 在旧浏览器上测试。

自动化测试分层

层级 覆盖对象
单元测试 边界用例
集成测试 错误场景
E2E 测试 关键路径
视觉回归测试 布局/视觉变化
可访问性测试 axe、WAVE 等工具

值得留意的是,在 Impeccable 的命令体系中这些能力并非全部由 harden 独扛:技术质量角度的系统性检查由 audit 命令(reference/audit.md)覆盖。实际工作中两者是先后关系——audit 负责查出问题,harden 负责针对错误处理、i18n、溢出与边界场景做修复。

五、加固的底线与收尾

规范用一组禁止项锁住加固质量,避免半途而废式的"看起来没问题":

NEVER(永不)

  • 假设输入完美——所有输入都要校验;
  • 忽略国际化——为全球用户设计;
  • 使用笼统的通用错误文案(如 "Error occurred");
  • 忘记离线场景;
  • 只信客户端校验;
  • 给文本用固定宽度;
  • 假设文本都是英文长度;
  • 单个组件出错就阻断整个界面。

规范同时强调:"Hardening is about expecting the unexpected. Real users will do things you never imagined."

六、加固验收清单:收尾前逐项打勾

在提交之前,用下列极端场景做一轮针对性验收(规范的 Verify Hardening 一节):

  • 长文本:尝试 100+ 字符的姓名;
  • Emoji:在所有文本字段中使用 emoji;
  • RTL:用阿拉伯语或希伯来语测试;
  • CJK:用中文/日文/韩文测试;
  • 网络问题:断开网络、节流连接;
  • 大数据集:用 1000+ 条数据测试;
  • 并发操作:快速连续点击提交 10 次;
  • 错误:强制触发 API 错误,测试所有错误态;
  • 空数据:删光数据,测试空状态。

当上述边界用例全部覆盖后,规范给出的下一步是固定的:交接给 /impeccable polish 做最终收尾(在 skill/plugin/ 版本中写作 {{command_prefix}}impeccable polish)。这体现的是一种分工理念:harden 负责"扛住真实世界的恶劣输入",polish 负责"上线前的最后视觉与细节打磨",二者一前一后构成完整的上线前流水线,而不是把加固留到最后一刻。

七、从文档到代码:规范在仓库中的落地脉络

如果希望深入本仓库核实本文依据,可以按以下路径对照阅读:

把它们串起来就能看到,harden 规范不是一份孤立的清单,而是 Impeccable 生产级设计工作流中"抗风险"这一环的标准动作:当 AI Agent 收到加固类请求时,按命令元数据路由到本规范,逐维修复错误处理、i18n、文本溢出与边界场景,最后用验收清单自检并交接给 polish。对任何团队而言,这套"先盘点风险 → 分维度加固 → 极端数据验收 → 交接打磨"的方法,都可以直接搬进自己的前端交付流程。

登录后查看全文
热门项目推荐
相关项目推荐