mcpField
H
harden

harden

github.com/aladicf设计与 UI46564 次安装23 周前更新
代码仓库

关于 harden

面向前端开发者和 Agent 的设计技能,帮助界面应对边界情况、错误、本地化问题及真实使用压力,并指导内容、状态、权限和恢复流程的韧性改进。

主要功能

  1. 01测试极端输入与错误场景
  2. 02改进文本溢出和本地化
  3. 03设计错误处理与恢复
  4. 04处理空状态、加载和权限状态
  5. 05保护高影响操作
  6. 06加固媒体与输入处理

适用场景

  1. 01让表单适应冗长或多样输入
  2. 02改善网络或 API 错误后的恢复
  3. 03提升界面对不同语言和地区的适应性
  4. 04降低批量或破坏性操作的风险

安装

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

$npx skills add https://github.com/aladicf/better-web-ui --skill harden

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

详细介绍

强化界面,以应对边界情况、错误、国际化问题,以及会破坏理想化设计的真实使用场景。

将边界情况视为设计输入,而不是在理想流程已经上线后才进行的收尾工作。

设计错误、警告、成功和信息状态时,请参考语义颜色,确保语义色彩清晰明确,而非纯粹用于装饰。 加固通知流、动态消息、摘要或提醒设置,避免造成疲劳和过多干扰时,请参考状态沟通。 加固用户上传的媒体、截图、图标缩放或图像溢出行为时,请参考图像处理。 任务涉及验证行为、摘要、严格验证器、可恢复的字段错误,或因恢复设计不佳而导致用户放弃时,请参考错误恢复。 加固登录、会话过期、密码设置、多重身份验证、账户锁定或账户恢复流程时,请参考身份验证与账户恢复。 加固角色编辑器、访问权限申请流程、403 错误恢复、管理员与成员界面、能力边界或高风险权限变更时,请参考权限与角色 UX。 加固语言选择器、区域设置覆盖项、货币或配送偏好,或可能因旅行、VPN 或多语言情况而失败的区域设置切换流程时,请参考语言与区域设置选择。 加固键盘支持、焦点指示器、跳过链接、隐藏内容行为、模态框焦点管理,或自定义与第三方组件的无障碍声明时,请参考组件无障碍。 当失败情况需要专门的路由级恢复页面,例如 401、403、404、429、500 或 503 状态时,请参考空状态模式。 加固必须在压力、紧迫、运营压力或紧急情况下仍保持易用的工作流时,请参考交互设计。 加固加载状态、过时数据提示、骨架屏的使用,或可能掩盖脆弱实际行为、却看似性能良好的状态时,请参考加载反馈与感知性能。 当界面在技术上可用,却因反复出现的细微卡顿、状态丢失、悬停陷阱、反馈不足或类似小问题而显得不稳定、不可靠或有损信任时,请参考微小故障与感知质量。

必须进行的准备

用户通过 /harden 启动此工作流。此技能激活后,加载 $frontend-design — 其中包含设计原则、反模式和上下文收集协议。继续之前,请遵循该协议;如果尚无设计上下文,必须先加载 $setup。此外,还要收集最可能破坏当前流程的风险场景、边界情况和用户限制。

评估加固需求

找出弱点和边缘情况:

  1. 使用极端输入进行测试:
    • 非常长的文本(名称、描述、标题)
    • 非常短的文本(空内容、单个字符)
    • 特殊字符(表情符号、从右向左书写的文本、变音符号)
    • 大数值(百万、十亿)
    • 大量条目(1000+ 个列表项、50+ 个选项)
    • 无数据(空状态)
  • 不便处理的媒体(微小图标、巨型屏幕截图、裁剪或背景颜色杂乱的用户上传图片)
  1. 测试错误场景:
    • 网络故障(离线、网速慢、超时)
    • API 错误(400、401、403、404、500)
    • 验证错误
  • 验证器过于严格,或格式要求不匹配
  • 表单、多步流程和叠加层中的浏览器前进/后退行为
  • 权限错误
  • 速率限制
  • 并发操作
  1. 测试国际化:

    • 较长的译文(德语通常比英语长 30%)
    • 从右向左书写的语言(阿拉伯语、希伯来语)
    • 字符集(中文、日语、韩语、表情符号)
    • 日期/时间格式
    • 数字格式(1,000 与 1.000)
    • 货币符号
  2. 测试高压使用场景:

  • 小型或分屏工作区
  • 嘈杂、频繁受打断的环境
  • 需要快速决策、耐心有限
  • 需要一个明确的下一步,而不是密集的控件墙的用户

重要:只适用于完美数据的设计还不能用于生产环境。请针对现实情况进行加固。

加固维度

系统性地提升韧性:

文本溢出与换行

长文本处理:

/* 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:显示服务器错误状态,并提供重试,以及安全的备用方案或支持途径
    • 503:显示维护或临时服务中断状态,并在可用时告知状态/预计恢复时间

如果故障影响整个路由,应将其设计为专用错误页面,而不是微小的行内消息或提示气泡。

优雅降级:

  • 核心功能无需 JavaScript 也能正常工作
  • 图片应有替代文本
  • 渐进增强
  • 为不受支持的功能提供回退方案
边缘情况与边界条件
能力越强,责任越大

功能越强大,界面就越需要清楚地说明可能造成的后果,并防止意外损害。

高影响功能包括:

  • 批量操作
  • 管理面板
  • 权限编辑器
  • 自动化与集成
  • 能够更改或生成大量内容的 AI 工具
  • 具有破坏性的编辑、发布、计费和账户操作

应添加的防护措施:

  • 基于角色的权限和明确的能力边界
  • 在执行高影响操作前提供预览、摘要或数量统计
  • 可撤销的操作提供撤销功能;不可逆或成本高昂的操作要求确认
  • 对组织有影响的操作提供审计跟踪或可见的历史记录
  • 安全的默认设置、明确的警告,以及通俗易懂的后果说明

应让用户感到能力可控,而非充满风险。如果某项功能可能造成大范围错误,就应设计界面,让用户在操作发生前了解将会发生什么。

空状态:

  • 列表中没有项目
  • 没有搜索结果
  • 没有通知
  • 没有可显示的数据
  • 提供明确的下一步操作

通知边缘情况:

  • 通知量激增(短时间内事件过多)
  • 重复或近似重复的通知
  • 状态变更后未读徽标仍显示过时信息
  • 未遵守免打扰时段、静音或延后通知设置
  • 需要摘要而非实时打扰的用户

加载状态:

  • 初始加载
  • 分页加载
  • 刷新
  • 显示正在加载的内容(“正在加载你的项目……”)
  • 为长时间操作提供预计耗时

大型数据集:

  • 分页或虚拟滚动
  • 搜索/筛选功能
  • 性能优化
  • 不要一次性加载全部 10,000 个项目

并发操作:

  • 防止重复提交(加载时禁用按钮)
  • 处理竞态条件
  • 使用乐观更新,并在失败时回滚
  • 解决冲突

权限状态:

  • 无权查看
  • 无权编辑
  • 只读模式
  • 清楚说明原因
  • 在适当情况下,说明如何申请访问权限或了解由谁管理该权限

浏览器兼容性:

  • 为现代功能提供 polyfill
  • 为不受支持的 CSS 提供回退方案
  • 检测功能,而非检测浏览器
  • 在目标浏览器中进行测试
图片、屏幕截图与用户媒体

用户上传的图片:

  • 将图片限制在受控容器中,并设置合理的宽高比
  • 使用 cover/裁剪,而不是保留会破坏网格布局的混乱固有布局
  • 当图片与页面背景融为一体时,使用细微的内阴影或内边框,避免背景渗透

屏幕截图:

  • 注意避免将屏幕截图缩得太小而无法阅读
  • 细节很重要时,优先使用更紧凑的裁剪图、局部屏幕截图,或在源布局尺寸较小时截取的屏幕截图

图标与视觉素材:

  • 不要将微小图标放大到远超其设计尺寸
  • 不要将细节丰富的图稿缩得过小,以致模糊不清
输入验证与清理
表单和输入中的 Postel 法则

界面输出应当保守;只要系统能够安全地进行规范化,就应宽容对待无害的输入差异。

良好的弹性处理方式:

  • 只要含义仍然明确,就接受带或不带空格、短横线或国家代码标点的电话号码
  • 自动去除首尾空白,而不是因为粘贴的值不符合必填项要求就直接报错
  • 当大小写无关紧要时,对标识符、标签和搜索查询采用一致的大小写处理方式
  • 优雅地规范化粘贴的内容,而不是因为用户从其他工具带来数据就惩罚他们
  • 失败时保留用户的原始输入,让修正更容易

只有在歧义、安全或不可逆错误确实重要时才严格要求。目标不是为了宽松而宽松,而是减少不必要的精细操作。

客户端验证:

  • 必填字段
  • 格式验证(邮箱、电话、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