Impeccable `/harden` 实战指南:为生产环境加固 AI 生成的界面——错误处理、国际化、文本溢出与边界条件
Impeccable 是一套面向 AI 编码代理(Claude、Cursor、Codex、Gemini CLI 等)的设计指南技能(skill),其 harden 命令负责让界面在"不完美数据"下依然可用。本文以仓库中的命令参考文档 skill/reference/harden.md 为骨架,系统讲解如何评估加固需求、沿七个维度实施加固、设计测试策略并最终验收,让前端不再只对理想数据有效。读完你将掌握一套可直接用于生产界面的加固检查表与对应 CSS/JS 实现模式。
为什么需要 harden:真实用户不会提供"完美数据"
设计稿里的一切都恰到好处——文案恰好一行、数据总有值、网络永远在线。但凡是交付给真实用户的产品,都要面对长文本、空数据、断网、报错、慢连接、RTL 语言、超长列表等状况。
.claude/skills/impeccable/reference/harden.md(该文件由 skill/SKILL.src.md 分发,仓库中以 .claude、.agent、.gemini、.cursor、plugin/skills、skill 等目录并存多份等价副本)在开篇就给出论断:
Designs that only work with perfect data aren't production-ready. Harden the interface against the inputs, errors, languages, and network conditions that real users will throw at it.
在 Impeccable 的命令体系中,harden 归类于 "Refine"(精修)类别。根据 README.md 的命令表,它负责 错误处理、i18n、文本溢出与边界情况;而在 scripts/lib/skill-categories.js 中,harden 与 polish、optimize、onboard 同属更上层的 harden 类别,意思是"把界面打磨到生产可用"。
命令元数据 skill/scripts/command-metadata.json 对其触发场景的界定是:当用户要求"加固(harden)、做到生产可用(make production-ready)、处理边界情况(edge cases)、增加错误态(error states)、修复溢出与 i18n 问题"时使用。典型用法与 README 的示例一致:
/impeccable harden checkout # Add error handling + edge cases
即:/impeccable harden [target] 对指定目标(如 checkout 流程)做整体加固。
第一步:评估加固需求(Assess Hardening Needs)
动手加固前,先系统性地找出薄弱点。原文档给出三大类评估手段,应逐条对目标界面自问。
1. 极端输入测试
| 输入类别 | 具体测试样例 |
|---|---|
| 超长文本 | 很长的名字、描述、标题 |
| 超短文本 | 空字符串、单个字符 |
| 特殊字符 | emoji、RTL 文本、重音符号 |
| 大数字 | 百万级、十亿级 |
| 大量条目 | 1000+ 条列表项、50+ 个选项 |
| 无数据 | 空状态(empty states) |
2. 错误场景测试
- 网络失败:离线、慢速、超时;
- API 错误:400、401、403、404、500;
- 校验错误(validation errors);
- 权限错误(permission errors);
- 限流(rate limiting);
- 并发操作(concurrent operations)。
3. 国际化测试
- 长翻译文本:德语通常比英语长 30%;
- RTL 语言:阿拉伯语、希伯来语;
- 字符集:中文、日文、韩文(CJK)、emoji;
- 日期/时间格式差异;
- 数字格式差异(
1,000与1.000); - 货币符号差异。
CRITICAL:Designs that only work with perfect data aren't production-ready. Harden against reality.
值得一提的背景是:Impeccable 不止有 harden 这类 LLM 驱动的指导命令。项目同时内置 61 条确定性检测规则(deterministic detector rules),可由 CLI 与浏览器扩展在不调用 LLM、不需要 API Key的情况下直接运行(见 README.md),并在 UI 文件编辑后由 hook 自动触发,把溢出、遮挡、对比度等问题反馈回来。这意味着"加固"在 Impeccable 里是双通道的:harden 提供方向性指导,检测器规则提供客观回环。仓库测试夹具 tests/fixtures/antipatterns 中就保存着大量待判定样例,例如 text-overflow.html、text-occlusion.html、script-error.html、body-text-viewport-edge.html,覆盖了超长文本越界、文本被遮挡、脚本错误引发布局问题等典型反例,可作为加固前后的对照参考。
第二步:沿七个加固维度系统改进
评估完成后,按以下维度逐一加固。每个维度都对应一组可在实际代码中直接落地的模式。
维度一:文本溢出与换行(Text Overflow & Wrapping)
超长文本的三种处理策略——省略号截断、多行截断、允许换行:
/* Single line with ellipsis */
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Multi-line with clamp */
.line-clamp {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Allow wrapping */
.wrap {
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
}
Flex/Grid 容器溢出:flex/grid 子项的默认 min-width: auto 会阻止内容收缩,导致长内容把布局撑破;需要显式放行收缩:
/* Prevent flex items from overflowing */
.flex-item {
min-width: 0; /* Allow shrinking below content size */
overflow: hidden;
}
/* Prevent grid items from overflowing */
.grid-item {
min-width: 0;
min-height: 0;
}
响应式字号:原文档给出的三条原则值得注意,尤其是与 16px 移动端底线的关系——这是整份技能在 skill/reference/typeset.md(排版指南)中反复强调的可读性下限在加固阶段的延续:
- 使用
clamp()实现流式排版(fluid typography); - 设定最小可读字号:移动端正文 16px,与排版指南的底线一致;只有真正次要的文本才允许 14px。原因:iOS Safari 会对小于 16px 的聚焦输入框强制放大(force-zoom),从而破坏表单布局;
- 测试文本缩放(放大到 200%);
- 确保容器能随文本扩张。
维度二:国际化(i18n)
文本膨胀预算:
- 为翻译文本预留 30%–40% 的空间余量;
- 用能自适应内容的 flexbox/grid 布局;
- 用最长的语言(通常是德语)测试;
- 避免在文本容器上使用固定宽度。
// ❌ Bad: Assumes short English text
<button className="w-24">Submit</button>
// ✅ Good: Adapts to content
<button className="px-4 py-2">Submit</button>
RTL(从右到左)支持:优先使用 CSS 逻辑属性(logical properties)而非物理属性,这样同一份样式在 LTR 与 RTL 下都会自动正确:
/* Use logical properties */
margin-inline-start: 1rem; /* Not margin-left */
padding-inline: 1rem; /* Not padding-left/right */
border-inline-end: 1px solid; /* Not border-right */
/* Or use dir attribute */
[dir="rtl"] .arrow { transform: scaleX(-1); }
字符集支持:
- 全站使用 UTF-8 编码;
- 用中文/日文/韩文(CJK)字符测试;
- 用 emoji 测试(单个 emoji 可达 2–4 字节);
- 覆盖不同书写系统:拉丁、西里尔、阿拉伯文等。
日期/时间与数字格式化:不要手拼格式字符串,交给 Intl API——同一日期在不同 locale 下输出完全不同(1/15/2024 对 15.1.2024):
// ✅ Use Intl API for proper formatting
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)规则:英语只有单/复数两种形态,而很多语言(如俄语、阿拉伯语)的复数规则复杂得多,靠 count !== 1 ? 's' : '' 拼接必然出错:
// ❌ Bad: Assumes English pluralization
`${count} item${count !== 1 ? 's' : ''}`
// ✅ Good: Use proper i18n library
t('items', { count }) // Handles complex plural rules
维度三:错误处理(Error Handling)
网络错误:展示清晰的错误信息、提供重试按钮、说明发生了什么、如适用则提供离线模式、处理超时场景。错误状态必须带恢复路径,而不是死路:
// Error states with recovery
{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 文本;
- 渐进增强(progressive enhancement);
- 为不支持的特性提供回退方案。
维度四:边界情况与临界条件(Edge Cases & Boundary Conditions)
空状态(empty states):覆盖"列表无条目 / 搜索无结果 / 无通知 / 无数据可展示"四类空态,并给出清晰的下一步动作。这与 Impeccable 的 onboard 命令(first-run flows、empty states、activation paths,见 README.md)形成互补:onboard 负责设计空态与激活路径的体验,harden 负责确保这些状态在任意缺失数据下都不会崩溃。
加载状态(loading states):覆盖初次加载、分页加载、刷新;说明正在加载什么(如 "Loading your projects...");长操作为用户提供时间预期。
大数据集:
- 分页或虚拟滚动(virtual scrolling);
- 提供搜索/过滤能力;
- 做性能优化;
- 不要一次性加载全部 10000 条数据。
并发操作:
- 防止重复提交(加载期间禁用按钮);
- 处理竞态条件(race conditions);
- 乐观更新并带回滚(optimistic updates with rollback);
- 冲突解决(conflict resolution)。
权限状态:
- 无查看权限、无编辑权限、只读模式都要有清晰表现;
- 明确解释"为什么"。
浏览器兼容性:
- 为新特性提供 polyfill;
- 为不支持的 CSS 提供回退;
- 用特性检测(feature detection)而不是浏览器检测(browser detection);
- 在目标浏览器中实测。
维度五:输入校验与净化(Input Validation & Sanitization)
客户端校验:必填字段、格式校验(email、phone、URL)、长度限制、模式匹配、自定义校验规则。
服务端校验(永远要做):绝不只信任客户端;所有输入都要校验并净化;防范注入攻击;实施限流。
约束处理示例:给输入框明确约束,并用 aria-describedby 关联帮助文本,让约束对辅助技术同样可见:
<!-- Set clear constraints -->
<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>
维度六:无障碍韧性(Accessibility Resilience)
键盘导航:
- 所有功能都可键盘访问;
- 逻辑化的 Tab 顺序;
- 弹窗(modal)中的焦点管理;
- 长内容提供跳转链接(skip links)。
读屏器支持:
- 恰当的 ARIA 标签;
- 用 live regions 播报动态变化;
- 描述性的 alt 文本;
- 语义化 HTML。
高对比模式:
- 在 Windows 高对比模式下测试;
- 不只依赖颜色传达信息;
- 提供替代的视觉线索。
无障碍与性能、响应式一样,同属 Impeccable 中 audit 命令(technical quality checks: a11y, performance, responsive,见 README.md)的检查范围;harden 关注的是让这些能力在异常条件下依然成立——例如错误播报、焦点在异步失败后的去向。
维度七:性能韧性(Performance Resilience)
慢连接:
- 渐进式图片加载(progressive image loading);
- 骨架屏(skeleton screens);
- 乐观 UI 更新;
- Service Worker 提供离线支持。
内存泄漏:卸载时清理事件监听器、取消订阅、清掉定时器/interval、中止未完成的请求(abort pending requests on unmount)——React/Vue 组件卸载后仍然 setState 的报错多源于此。
节流与防抖:
// Debounce search input
const debouncedSearch = debounce(handleSearch, 300);
// Throttle scroll handler
const throttledScroll = throttle(handleScroll, 100);
测试策略(Testing Strategies)
加固必须可验证,原文档给出手动与自动化两条路径。
手动测试:
- 用极端数据测试(超长、超短、空);
- 用不同语言测试;
- 离线测试;
- 限速到 3G 模拟慢连接;
- 用读屏器测试;
- 纯键盘导航测试;
- 在旧浏览器上测试。
自动化测试:
- 针对边界情况的单元测试;
- 针对错误场景的集成测试;
- 覆盖关键路径的 E2E 测试;
- 视觉回归测试(visual regression tests);
- 无障碍测试(axe、WAVE)。
IMPORTANT:Hardening is about expecting the unexpected. Real users will do things you never imagined.
NEVER 清单(加固期间绝对禁止的事项,值得逐条对照自查):
- 假设输入完美(一切都要校验);
- 忽视国际化(要为全球用户设计);
- 错误信息留空泛文案(如 "Error occurred");
- 忘记离线场景;
- 只信客户端校验;
- 文本容器用固定宽度;
- 假设文本是英文长度;
- 单个组件出错就阻塞整个界面。
最终验收:Verify Hardening
用真实边界条件做最后一轮地毯式测试:
- 长文本:用 100+ 字符的名字测试;
- emoji:在所有文本字段里输入 emoji;
- RTL:用阿拉伯语或希伯来语测试;
- CJK:用中文/日文/韩文测试;
- 网络问题:断开网络、限速连接;
- 大数据集:用 1000+ 条数据测试;
- 并发操作:快速连点提交按钮 10 次;
- 错误:强制触发 API 错误,遍历所有错误状态;
- 空数据:移除全部数据,测试空状态。
当上述边界情况全部覆盖后,原文档给出的流程收尾是:把成果移交给 /impeccable polish 做最后一遍整体打磨(polish 对应命令参考见 skill/reference/polish.md,负责 final pass、设计系统对齐与发布就绪检查)。
小结:把"加固"沉淀为工作习惯
结合 Impeccable 的整体设计可以看出,harden 不是孤立的一次性操作,而是与 init(沉淀产品事实)、audit(技术质量检测)、onboard(空态与激活路径)、polish(发布前终审)共同构成的产线环节。它解决的是 AI 生成界面最容易暴露的一类缺陷——"只在演示数据下好看"。评估加固需求、沿七维度逐项加固、分层测试、按验收清单放行,四步走完,界面才算真正具备生产资格。建议将这些模式沉淀到团队的通用样式与组件库中(如 .truncate、.line-clamp、min-width: 0 约定、逻辑属性规范),让每一次新界面生成都默认带上加固基因。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00