关于 harden
harden 是一项设计技能,用于检查界面在边界情况和现实故障下的表现。它涵盖输入、错误处理、无障碍、性能和国际化等方面的韧性检查。
主要功能
- 01测试极端输入和空数据
- 02检查网络与 API 错误
- 03改善国际化支持
- 04处理无障碍与性能问题
- 05检查引导和加载状态
适用场景
- 01检查表单对无效或超长输入的处理
- 02让布局适应 RTL 和翻译文本
- 03规划网络故障后的恢复行为
- 04测试空状态和大型数据集
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ pbakaus/ impeccable --skill harden安装后在 Claude Code 中输入/harden确认已加载。
详细介绍
增强界面,使其能够应对边界情况、错误、国际化问题以及会破坏理想化设计的真实使用场景。
评估加固需求
识别薄弱环节和边界情况:
-
使用极端输入进行测试:
- 超长文本(名称、描述、标题)
- 超短文本(空文本、单个字符)
- 特殊字符(表情符号、从右向左书写的文本、带变音符号的字符)
- 大数值(百万、十亿)
- 大量条目(1000+ 个列表项、50+ 个选项)
- 无数据(空状态)
-
测试错误场景:
- 网络故障(离线、缓慢、超时)
- API 错误(400、401、403、404、500)
- 验证错误
- 权限错误
- 速率限制
- 并发操作
-
测试国际化:
- 较长的译文(德语通常比英语长 30%)
- RTL 语言(阿拉伯语、希伯来语)
- 字符集(中文、日语、韩语、表情符号)
- 日期/时间格式
- 数字格式(1,000 与 1.000)
- 货币符号
重要:只适用于完美数据的设计尚未达到可用于生产环境的标准。应针对实际情况进行加固。
加固维度
系统性地提升韧性:
文本溢出与换行
长文本处理:
/* 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 溢出:
/* 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;
}
响应式文本大小:
- 使用
clamp()实现流式排版 - 设置最小可读字号(移动设备上为 14px)
- 测试文本缩放(缩放至 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(从右向左)支持:
/* 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)字符进行测试
- 使用表情符号进行测试(每个表情符号可能占 2-4 个字节)
- 处理不同的文字体系(拉丁文、西里尔文、阿拉伯文等)
日期/时间格式:
// ✅ 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
复数形式:
// ❌ Bad: Assumes English pluralization
`${count} item${count !== 1 ? 's' : ''}`
// ✅ Good: Use proper i18n library
t('items', { count }) // Handles complex plural rules
错误处理
网络错误:
- 显示清晰的错误消息
- 提供重试按钮
- 说明发生了什么
- 提供离线模式(如适用)
- 处理超时场景
// 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:显示通用错误,并提供获取支持的方式
优雅降级:
- 即使没有 JavaScript,核心功能也能正常运行
- 图片应有替代文本
- 渐进式增强
- 为不受支持的功能提供回退方案
边界情况与临界条件
空状态:
- 列表中没有条目
- 没有搜索结果
- 没有通知
- 没有可显示的数据
- 提供清晰的后续操作
加载状态:
- 初始加载
- 分页加载
- 刷新
- 显示正在加载的内容(“正在加载你的项目……”)
- 为耗时较长的操作提供时间估计
大型数据集:
- 分页或虚拟滚动
- 搜索/筛选功能
- 性能优化
- 不要一次性加载全部 10,000 个条目
并发操作:
- 防止重复提交(加载期间禁用按钮)
- 处理竞态条件
- 使用乐观更新,并在失败时回滚
- 解决冲突
权限状态:
- 无权查看
- 无权编辑
- 只读模式
- 清楚说明原因
浏览器兼容性:
- 为现代功能提供 polyfill
- 为不受支持的 CSS 提供回退方案
- 进行功能检测(而非浏览器检测)
- 在目标浏览器中测试
新手引导与首次使用体验
适用于生产环境的功能应服务首次使用的用户,而不只是高级用户。设计能帮助新用户快速获得价值的路径:
空状态:每个无数据页面都需要:
- 说明或插图,展示这里将显示什么
- 说明这对用户为何重要
- 明确的 CTA,用于创建第一项内容或从模板开始
- 有吸引力的视觉设计(不能只是一片空白,上面写着“还没有内容”)
需要处理的空状态类型:
- 首次使用:突出价值,提供模板
- 用户已清空:轻量提示,便于重新创建
- 无搜索结果:建议更换查询,提供清除筛选条件的选项
- 无权限:说明原因以及如何获取访问权限
首次使用体验:尽快帮助用户获得“顿悟时刻”。
- 展示而非讲解——用可运行的示例代替说明
- 渐进式呈现——一次教一件事,不要一开始就讲完所有内容
- 让新手引导成为可选项——允许有经验的用户跳过
- 提供智能默认值,将必要设置降到最低
功能发现:在用户需要时介绍功能,而不是提前讲解。
- 在使用位置提供情境化提示(简短、可关闭、仅显示一次)
- 为新功能或未使用的功能添加徽标或指示标记
- 安静地庆祝功能启用事件(使用 Toast,而不是模态框)
绝不要:
- 在用户能够使用产品前强制进行冗长的新手引导
- 反复显示相同的工具提示(记录用户的关闭操作并予以尊重)
- 在引导式演示期间阻塞整个 UI
- 创建与真实产品脱节的独立教程模式
- 设计只写着“没有内容”、却不提供下一步操作的空状态
输入验证与清理
客户端验证:
- 必填字段
- 格式验证(电子邮件、电话、URL)
- 长度限制
- 模式匹配
- 自定义验证规则
服务端验证(始终执行):
- 绝不要只信任客户端
- 验证并清理所有输入
- 防范注入攻击
- 速率限制
约束处理:
<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>
无障碍韧性
键盘导航:
- 所有功能均可通过键盘访问
- 合理的 Tab 顺序
- 在模态框中管理焦点
- 为长内容提供跳转链接
屏幕阅读器支持:
- 使用恰当的 ARIA 标签
- 播报动态变化(实时区域)
- 提供描述性替代文本
- 使用语义化 HTML
动作敏感性:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
高对比度模式:
- 在 Windows 高对比度模式下进行测试
- 不要只依赖颜色
- 提供其他视觉提示
性能韧性
网络连接缓慢:
- 渐进式加载图片
- 骨架屏
- 乐观 UI 更新
- 离线支持(service workers)
内存泄漏:
- 清理事件监听器
- 取消订阅
- 清除计时器/间隔计时器
- 卸载时中止待处理请求
节流与防抖:
// Debounce search input
const debouncedSearch = debounce(handleSearch, 300);
// Throttle scroll handler
const throttledScroll = throttle(handleScroll, 100);
测试策略
手动测试:
- 使用极端数据进行测试(极长、极短、空)
- 使用不同语言进行测试
- 测试离线情况
- 测试慢速连接(限制为 3G)
- 使用屏幕阅读器进行测试
- 测试仅使用键盘的导航
- 在旧版浏览器中测试
自动化测试:
- 针对边界情况的单元测试
- 针对错误场景的集成测试
- 针对关键路径的 E2E 测试
- 视觉回归测试
- 无障碍测试(axe、WAVE)
重要:加固意味着预想到意料之外的情况。真实用户会做出你从未想象过的操作。
绝不要:
- 假设输入完美(验证所有内容)
- 忽视国际化(面向全球进行设计)
- 使用笼统的错误消息(“发生错误”)
- 忘记离线场景
- 只依赖客户端验证
- 为文本使用固定宽度
- 假设英文文本长度
- 在一个组件出错时阻塞整个界面
验证加固效果
使用边缘情况进行全面测试:
- 长文本:尝试使用长度超过 100 个字符的名称
- 表情符号:在所有文本字段中使用表情符号
- RTL:使用阿拉伯语或希伯来语进行测试
- CJK:使用中文、日语或韩语进行测试
- 网络问题:断开互联网连接、限制连接速度
- 大型数据集:使用 1000 多个项目进行测试
- 并发操作:快速点击提交按钮 10 次
- 错误:强制触发 API 错误,测试所有错误状态
- 空状态:删除所有数据,测试空状态
请记住:你要针对真实的生产环境进行加固,而不是追求演示效果的完美。要预料到用户会输入奇怪的数据、在流程中途断开连接,并以意想不到的方式使用你的产品。让每个组件都具备韧性。
评论
支持 Markdown