在互联网上最受欢迎的网站首页中,超过四分之一的图片,其替代文本存在缺失、含糊不清,或直接复制相邻图片描述的问题。
这一数据来自 WebAIM 的2026年 WebAIM Million 报告:在排名前一百万的网站首页中,16.2%的图片缺少 alt 文本。alt 是一个 HTML 属性,用文本描述图片内容。在确实提供 alt 文本的图片中,另有10.8%的描述缺乏信息,例如 alt="image"、原始文件名,或与相邻图片重复的描述。
自动化工具能够可靠地标记缺失的 alt 文本,却不太擅长修复质量差的描述。多数检查器只判断图片是否有可访问名称,而不判断该文本是否传达了有用信息。这是有意做出的设计选择:如果质量检查规则频繁误报,团队就会把它关闭。因此 alt="IMG_2847.png" 可以通过检查,五个不同星形图标使用同一段 alt="3/5 stars" 也可以。
我们开发了一个 alt 文本插件,用于 GitHub Accessibility Scanner,帮助改善替代文本。本文介绍我们如何划分检查器可以证明的问题与只能怀疑的问题,为什么最严重的缺陷最终属于布局问题而非解析问题,以及引入模型之后发生了什么。
如果你正在构建自己的自动检查,无论是否用于无障碍,这些取舍都值得参考。
不看图片,也能证明字符串有问题
alt 文本是否存在是客观事实:属性存在,或者不存在;而质量往往需要判断。机器不能仅凭标记就证明某个句子是否在具体语境中充分描述了图片。
不过,质量并不全是主观判断。有些检查只根据 alt 字符串就能完成,不必查看图片内容:
- 属性缺失——不是空字符串——或者只含空白字符。
- alt 是文件名,例如
hero.png、IMG_2847.jpg。 - alt 是原本打算替换的占位符,例如
TODO、tbd。 - alt 只有一个泛称,指出媒介而不描述内容,例如
image、logo、chart。 - 相邻图片重复使用同一段 alt。
这些都是针对字符串本身的判断,也由此形成了我们的分界线。五条确定性规则默认运行,不需要 AI 模型凭据,也不调用网络。另有一条可选规则,把图片内容及周围上下文交给模型,处理仅靠字符串无法支持的判断。
首先要决定扫描页面上哪些图片。我们使用 Playwright 基于角色的定位器,而不是 querySelectorAll('img'),因此不在浏览器无障碍树中的元素会被排除,包括带有 alt="" 的元素。最后这一点尤其重要:空 alt 表示作者明确声明图片是装饰性的;若将其标为错误,反而会惩罚我们希望鼓励的正确做法。
检查应有多严格?质量检查器能否被接受取决于误报,所以我们选择封闭词集合,而不是复杂的启发式算法。模糊 alt 规则先规范化字符串,再与一份本身不传达内容的精选词表比较,只有完全匹配才触发:
alt="image"会被标记。alt="image of the login screen with the SSO button highlighted"不会。
如此直白的规则会漏掉许多质量差的 alt,但我们宁愿接受漏报,也不愿产生误报:开发者愿意启用的可靠检查器,比会被关掉的检查器更有价值。
重复描述是布局问题,而不是 DOM 问题
重复 alt 带来了一个有趣问题:假设一行有五个星形图标,都写着 "3/5 stars"。屏幕阅读器用户会连续听到同一句话五遍,后四遍没有增加任何信息。
第一版按文档顺序遍历图片,标记连续出现的相同规范化 alt。它却也捕捉了不该标记的内容。例如,页脚与页首的 GitHub 标志在提取列表里可能紧邻,在屏幕上却相距很远,用户不会把它们当作一组。
重要的是图片在屏幕上的位置,而不是在标记中的顺序。因此,规则现在检查页面布局,只有两个边界框之间的距离相对于框自身足够小时,才会继续把它们归入同一段连续图片:
const gap = Math.max(horizontalGap, verticalGap)
const largerDim = Math.max(a.boundingBox.width, a.boundingBox.height,
b.boundingBox.width, b.boundingBox.height)
return gap > GAP_MULTIPLIER * largerDim这里有两点需要说明:
- 乘数是人为判断的结果,不是从某个公式推导出来的数值。应当依据真实页面调参,而不是把它当作规范给出的可信常量。
- 任意一张图片没有可测量边界框时,检查采用放行行为,连续序列继续延伸。漏掉的结果不可见,错误的结果却会直接呈现给用户。
让模型做审阅者,而不是挑剔的评论者
确定性规则只需要 alt 字符串。更智能的判断则必须理解页面内容,而图片元素本身没有记录这些信息。alt="a smiling person" 是否合适完全取决于周围语境:如果只是营造氛围的通用照片,可能足够;但如果标题已经点名某个人,这段描述就不够具体。
在可选的 alt-text-quality 检查中,我们为每张图片提取页面上下文:最近的标题、页面标题、任何 <figcaption>、图片是否位于链接或按钮中,以及附近最多600个字符的正文。
链接信号最重要,因为图片如果是链接的唯一内容,alt 就会成为链接的可访问名称。这时合适的 alt 应当指出链接目的地,而不是描述图片外观。
需要注意:插件只记录图片是否位于链接内部,没有检查它是否是该链接的唯一内容;而后者才是真正让 alt 成为链接名称的条件。因此,目前两种情况对模型而言没有区别。
这些上下文、alt 和图片通过 GitHub Models 发送给视觉模型。失败很少来自模型看错图片,而更多来自模型过于爱发表意见。面对完全合适的 alt,最初版本仍然会建议改写,因为语言模型对“还能更好吗”几乎总是回答“可以”。于是每张图片都成为问题,真正的信号被淹没了。
我们通过三项改动解决这一问题:
- 使用决策流程,而不是宽泛指令。提示词依次执行四个步骤,在首次匹配时停止,并输出相应判断:装饰性、与图注重复、功能性或信息性。
- 明确禁止吹毛求疵。尊重作者的表达框架。区分多余前缀“Image of…”和具有语义的“Photograph of…”。如果周围正文已经分析图片,就把简短 alt 视为正确。
- 采用结构化输出,并强制字段顺序,使
reasoning先于verdict生成,要求模型先构建论证,再选择标签。
这些措施不能让模型永远正确,但能让它足够一致,以便迭代。仓库还提供一套离线评分工具,基于已发布的教学材料:WebAIM、W3C 图片教程和 POET。规则与评测工具共用一个提示词,因此离线调优的内容就是 CI 中运行的内容。不过,这套工具只测试模型判断,不测试完整流水线;某个案例在离线评测中可以得满分,在真实扫描中却可能根本到不了模型。
把图片发送给模型,是隐私与成本决策
检查一旦把网页数据发送给外部模型,就不再只是 lint 规则,而必须认真设计数据流。由此产生几项要求:
- 规则默认关闭。只有在插件配置中主动启用才会运行,而且需要有 GitHub Models 访问权限的令牌。
- URL 会被脱敏。图片 URL 和链接
href常含签名 CDN 令牌或会话标识,所以进入模型上下文或规则错误日志的 URL 都会移除查询参数与片段。同理,发送的标记中的src和srcset会替换为(omitted)。 - 上下文窗口中的所有内容都是不可信输入。标题、段落与正文均来自被扫描页面,页面中可能包含试图操纵模型的文字。结构化输出只能约束回复的形状,不能约束其背后的推理。
这里还有一项容易被过度解读的限制:问题报告仍然会把真实页面 URL 和原始 HTML 传入扫描器的常规报告流水线。这是刻意设计的,因为无法定位图片就无法修复。脱敏限制的是进入模型和日志的数据,而不是进入你自己 issue 的内容。另外,如果配置 Azure AI Vision 凭据,可选的 OCR 预处理会把图片字节发送到第二个服务。Azure 不是必需项,但数据流审查需要覆盖这两条路径。
成本也有类似特点。通常,每张图片在每次扫描中都会产生一次模型调用;在图片很多的网站上,这会成为整次运行的主要成本。仅这一点,就足以考虑定期扫描,而不是每次提交都运行。
目前仍然做不到什么
- 确定性规则只做字面判断。它们能识别明显没有认真写的 alt,不能识别流畅却错误的描述。它们读取的是
alt属性,而不是计算后的可访问名称,因此即使aria-label修复了问题,也不会阻止报告产生。 - 基于模型的规则会误报。每条报告都应当触发人工关注,而不是被当作最终裁定。
- 没有报告,不等于已经覆盖。这条规则会在浏览器会话之外重新获取图片,因此需要认证的图片可能加载失败。获取或模型错误会被记录并跳过,页面可能因为根本没检查到内容而显示“无问题”。
- 建议的 alt 只是草稿。只看到图片和附近几个词的模型,无法充分理解你的受众、行文风格,以及图片在整页中的作用。
- 部分报告会与扫描器内置检查重复,因为我们的
missing-alt规则覆盖了相同问题。 - 我们仅检查 HTML
<img>标签。SVG、role="img"容器、CSS 背景与 canvas 尚未覆盖。 - 这是新代码,真实场景反馈有限。这类规则需要面对真实网站多样的标记和内容才能改善;插件目前还没有足够经验,应据此看待早期报告。
- 通过检查,不等于符合无障碍标准。自动检查只是最低起点;最终目标是与使用辅助技术的人共同测试。
给类似检查器开发者的建议
将能够证明的问题与只能怀疑的问题分开,并采用不同默认设置。能够证明问题的检查应当便宜、可预测且默认开启。只能怀疑问题的检查应当由用户主动启用,并表现为建议而非裁定。然后,关注用户实际体验,而不是 DOM 所表达的结构。插件目前仍存在的每项差距都属于后者:我们记录图片位于链接内,却没有判断图片本身是否就是链接;我们读取属性,却没有读取计算后的名称。
这段距离才是真正的边界,更好的模型也无法自动弥合。要决定图片对无法看见它的用户有什么作用,仍然需要人类判断。自动化的价值,在于让人们把需要复查的图片找出来。
在你的无障碍扫描流程中试用 alt-text 插件。 如果它给出错误判断,请报告。提交一个 issue,附上问题报告;如果页面公开,也请附上页面链接。












暂无评论内容