antislop-human
反-套路:AI 编码代理规则。人类技能
属于 antislop 系统的一部分。请与
antislop.md(核心)一起阅读。本技能深入探讨人类关注的问题:UI 必须对不同视力、操作习惯和设备的用户保持可用。涵盖对比度、键盘、焦点、状态以及排除用户的移动端细节。
如何使用本技能
- 当任务涉及构建或编辑 UI 时,与
antislop.md一起加载。核心包含机制(目的测试、三个层级、交付门禁);本技能包含人类层面的深度:UI 中排除不同视力、操作习惯和设备的用户的部分。 - 每条目具有相同结构:说明(模式)、原因(它排除了谁,以及为什么它看起来未完成)、修复(应该怎么做),并引用核心规则 R-XX。
- 无障碍不是最后附加的检查清单。它是“UI 经得起考验”(C-4)这一核心承诺的一部分。核心中的“交付门禁”仍然是门禁;本文件末尾的“人类技能检查清单”是与之并行的补充。
- 对比度检查器(公式 + 参考表 + 脚本)位于本技能中。对于你无法用肉眼验证的每个颜色配对,请使用它。
- 本技能只保留移动端中排除用户的细节:缩放和屏幕键盘。
颜色与对比度
低对比度文本
- 说明: 浅灰色文本放在白色或近白色背景上,细体正文文本,因“优雅”而选择的柔和标签,但难以阅读。
- 原因: 它排除了低视力用户以及在强光下的所有人。这是一个未经标准检查而做出的视觉选择,这正是过滤器要捕捉的默认行为。
- 修复: 满足 WCAG AA 最低要求(R-25):普通文本 4.5:1,大文本(18px+)3:1。计算比率,不要目测。
照片或渐变上的文本
- 说明: 白色文本直接放置在图像或渐变上,而图像或渐变在某些区域较亮,且仅在一个亮点处检查。
- 原因: 对比度是局部的。在图像亮的区域,即使整体看起来还行,文本也会低于 4.5:1。R-25 要求测试文本经过的整个区域,而不是单个点。
- 修复: 在文本后面添加一个遮罩层或纯色块,然后验证最差位置,而不是最佳位置。如果文本区域的任何部分失败,则该处理方式失败。
灰上灰幻觉
- 说明: 声称“深灰上黑”或“浅灰上白”无需计算即可通过 AA 标准。
- 原因: 这是最常见的无障碍幻觉。人眼会高估灰色配对的对比度,代理会重复这一说法因为听起来合理。#555555 在黑色上实际为 2.8:1。它失败。
- 修复: 绝不断言一个配对通过。运行对比度检查器(如下)或应用公式。当二者都不可行时,使用参考表。
非文本对比度
- 说明: 交互组件(按钮、图标、输入边框、焦点指示器、图表分段)与其背景的区别小于 3:1。
- 原因: 非文本 UI 通过形状和边缘传递信息。当边缘只有一丝色调时,低视力用户无法找到控件。同样的标准也适用于悬停和选中状态。
- 修复: 为每个组件边界和每个状态指示器提供与相邻颜色 3:1 的对比度(WCAG 1.4.11)。将图标与满足 4.5:1 的文本标签配对。
对比度检查器
对比度检查器的所在地。三层,从最方便到最不方便:
脚本。 当脚本运行时可用且文件存在时,运行它而不是手动计算。脚本位于本技能的文件夹中(contrast-check.py,与 SKILL.md 同级)。在 macOS 和 Linux 上使用 python3 运行,在 Windows 上使用 python:
python3 "${CLAUDE_SKILL_DIR}/contrast-check.py" "#FFFFFF" "#777777"
# normal text: FAIL (4.48 < 4.5)
# large text: PASS (4.48 >= 3.0)
如果 ${CLAUDE_SKILL_DIR} 变量在此代理中不可用,请将脚本路径直接指向此技能文件夹。此脚本的存在是为了让代理停止幻觉 AA。它接收两个十六进制颜色,并打印比率以及两种文本大小的通过/失败判定。如果文件缺失,下面的公式和表格本身已足够。不要因为脚本而阻塞。
公式(WCAG 2.x)。
- 对比度比率 = (L1 + 0.05) / (L2 + 0.05),其中 L1 为较浅色的相对亮度,L2 为较深色的。
- 某颜色的相对亮度 L:将每个通道转换为 0-1(
c = hex / 255),然后线性化:如果c <= 0.03928,则c_lin = c / 12.92;否则c_lin = ((c + 0.055) / 1.055)^2.4。 L = 0.2126*R + 0.7152*G + 0.0722*B。- 比较未四舍五入的比率:普通文本 4.5:1,大文本(18px+,根据 R-25)3:1。仅显示时四舍五入,因此 4.498:1 的配对显示为 4.50 但仍未通过 4.5:1。最大比率为 21.0(黑底白字)。
参考表(常见配对,使用公式计算):
| 配对(文本于背景上) | 比率 | 普通文本 (4.5) | 大文本 (3.0) |
|---|---|---|---|
| 黑底白字 | 21.00 | 通过 | 通过 |
| 白底黑字 | 21.00 | 通过 | 通过 |
| #333333 上白色 | 12.63 | 通过 | 通过 |
| #666666 上白色 | 5.74 | 通过 | 通过 |
| 白色上 #777777 | 4.48 | 失败 | 通过 |
| #070707 上 #777777 | 4.50 | 失败 | 通过 |
| #888888 上白色 | 3.54 | 失败 | 通过 |
| #999999 上白色 | 2.85 | 失败 | 失败 |
| 黑色上 #555555 | 2.82 | 失败 | 失败 |
#070707 上 #777777 行是接近阈值的情况:4.4983:1 显示时四舍五入为 4.50,但仍未通过 4.5:1。
将该表作为合理性检查,而非替代。任何未列出的配对,或任何接近阈值的配对,都需要通过公式或脚本处理。
键盘
移除了焦点轮廓
- 说明:
outline: none或outline: 0且没有替换的焦点样式。 - 原因: 键盘用户看不到他们所在的位置。这是使 UI 无法在不使用鼠标的情况下使用的最快方式,而 R-32 明确禁止此做法。
- 修复: 保留或替换轮廓为可见的
:focus-visible样式,该样式满足相同的对比度标准(与相邻元素 3:1)。未经替换绝不要设置outline: none。
仅鼠标模式
- 说明: 仅在悬停时打开的菜单,可点击打开但不能键盘打开的下拉菜单,没有键盘备选方案的拖放操作。
- 原因: 每一种都排除了键盘和辅助技术用户(R-32)。如果一个控件不能通过 Tab、Enter 或 Space 键到达和操作,那么它对一群人来说就不存在。
- 修复: 每个交互元素都可以通过键盘到达和操作(R-32):符合视觉顺序的逻辑 Tab 顺序,使用 Enter 或 Space 激活,以及对话框可通过 Escape 关闭(R-26)。
打乱的 Tab 顺序
- 说明: 焦点在页面上跳跃,跳过内容,或落在隐藏元素上,因为 DOM 顺序与视觉顺序不匹配。
- 原因: 按照代码顺序而不是视觉顺序的 Tab 顺序使导航不可预测(R-32)。用户会丢失位置,页面感觉像坏了一样。
- 修复: 使源代码顺序与视觉顺序匹配,为长页面添加跳转链接,并且除非是受控焦点陷阱(如对话框)的一部分,否则不要给真实内容设置
tabindex="-1"。
焦点与状态
弱或不可见的焦点指示器
- 说明: 与背景颜色相同的焦点环,仅悬停时出现的环,或比 1px 边框更细的指示器。
- 原因: 焦点指示器是键盘用户知道他们所在位置的方式。如果它未通过对比度标准或仅悬停时显示,则纯键盘使用会中断(R-32、R-34)。
- 修复: 在每个交互元素上都有可见的焦点指示器,与相邻颜色对比度为 3:1,在你提供的每个主题中。在深色和浅色模式下检查。
仅颜色反馈
- 说明: 仅通过颜色传达的成功、错误和状态:红色错误文本、绿色成功边框、带色调的芯片,没有图标、标签或文本。
- 原因: 它排除了色盲和低视力用户,并且在强制颜色模式下完全消失。依赖看到色调的状态不是真正的状态(C-4)。
- 修复: 将每个颜色信号与文本、图标或模式配对。错误状态首先是文本:“密码必须至少 8 个字符”,而不仅仅是一个红色边框。
缺少 UI 状态
- 说明: 没有空状态、加载状态或错误状态的数据视图,或状态存在但不可见:无文本的旋转加载器、无解释的空白屏幕。
- 原因: R-27 要求这三种状态;从无障碍角度看,每个状态必须是可感知和信息性的,而非装饰性的。没有上下文的加载旋转器对屏幕阅读器用户来说是页面冻结。
- 修复: 每个数据视图都有所有三种状态(R-27),每个状态都被宣告或可见:明确的空消息、带文本的加载状态、以及说明发生了什么以及如何继续的错误状态。
缩放与移动端使用
移动端的布局机制(断点、缩放、网格、溢出、点击目标)是 antislop-layoutmobile 的职责。本节只保留移动端中排除用户的细节:缩放和屏幕键盘。
无法缩放的文本
- 说明: 固定的像素字体大小,或带有
overflow: hidden的容器在 200% 缩放时裁剪文本。 - 原因: 用户必须能够调整文本大小(WCAG 1.4.4)。如果缩放到 200% 会裁剪内容或强制水平滚动,那么文本在实践中不可调整大小。
- 修复: 随缩放重新排列的动态字体,文本容器不裁剪,并在窄视口上验证布局在 200% 缩放时保持稳定(R-35)。
移动键盘遮挡表单
- 说明: 视口底部的输入框被屏幕键盘遮挡,没有滚动到可见区域,也没有为输入留出空间。
- 原因: 用户看不到或够不到的表单是他们无法完成的表单。这是移动端独有的排除问题(R-03)。
- 修复: 当输入框获得焦点时,它应该滚动到键盘上方,并有足够的底部内边距,使焦点字段永远不会被覆盖。在真实设备或模拟键盘上进行测试。
人类技能检查清单
当任务涉及 UI 时,请与核心“交付门禁”一起运行这些检查。所有答案必须为“是”:
- 每个文本和背景配对是否已使用对比度检查器(公式、表格或脚本)验证,包括图像和渐变上的文本?(R-25)
- 每个交互组件边界和状态指示器是否满足与其背景 3:1 的对比度?(非文本对比度)
- 焦点指示器是否在每个主题的每个交互元素上可见、高对比度且存在?(R-32、R-34)
- 每个交互元素是否可通过键盘到达和操作,对话框是否可通过 Escape 关闭,且没有未经替换的
outline: none?(R-32、R-26) - 每个数据视图的空、加载和错误状态是否都存在且可感知,而非仅依赖颜色?(R-27、C-4)
- 文本是否可以缩放到 200% 而不被裁剪,并且移动键盘是否永远不会覆盖焦点输入框?(R-35)