
你可能遇到过这种场景项目上线前CI 跑完 axe 检查全部通过Lighthouse 无障碍评分打了 100 分WAVE 也没有报出任何红色错误。团队松了一口气认为可访问性验收已经完成了。但真正有视觉障碍的用户打开页面用屏幕阅读器浏览核心数据图表时听到的只有一句“公司2024年营收图表”——图表里的关键数字、增长趋势、业务结论全部丢失。问题出在哪儿自动化检查工具验证的是“规则”而不是“语义”。alt 文本合不合格关键不在它是否存在而在于它是否准确传递了图片在当前上下文中的信息。这个“语义层面”的判断目前任何自动化工具都无法完整承担。这篇文章会把 alt 文本的作用讲清楚拆解自动化检查的真实能力边界再给出一套“自动化检查兜底 人工语义评审兜住”的完整保障流程。读完你会发现真正拉开体验差距的不是检查工具而是团队对 alt 文本的理解深度。1. 为什么 alt 文本最近值得重新当回事很多前端团队对 alt 文本的印象还停留在“给图片加一个属性”的阶段。但最近几年这个看似基础的问题正在重新变得重要背后有几个实际原因。第一无障碍合规a11y开始进入更多项目的验收标准。无论是政务网站、金融业务还是大型企业内部系统产品验收时都会要求通过无障碍检查。alt 文本是其中最低门槛的一项几乎所有自动化工具都会先查它。也正因为门槛低很多团队把它当成一个“填空题”来处理随便填一句“图片”或“示意图”就算过关。第二图片的生产方式变了。现在页面上的图片大量来自图表工具自动导出、AI 生成、运营后台批量上传很多图片没有经过人工确认就直接进入前端。图片更新频繁alt 文本却常常停留在第一次写入的内容久而久之就出现了“图上已经改成 Q3 数据alt 还是 Q1 说法”这类问题。第三搜索引擎会读取 alt 文本它同时承担着图片 SEO 的作用。描述准确的 alt 文本能让图片搜索流量更精准但这只是附属价值不是主要目的。核心判断是alt 文本不是给搜索引擎看的装饰品也不是给自动化检查交差的答案。它是用户在无法看到图片时用文本形式继续理解页面信息的通道。把 alt 当成填空等于把这条通道堵上了。2. 先厘清基础alt 文本到底承担什么职责alt 是 HTML 中 img 标签的一个属性用于提供图片的替代文本。屏幕阅读器会朗读 alt 的内容图片加载失败时浏览器也会显示 alt 文本。img src/images/team-photo.png alt产品团队合照 /缺少 alt 属性时不同屏幕阅读器的表现不同有的会读文件名有的会读“图片”这类信息对用户完全没有意义。所以自动检查工具的第一项任务就是确保 img 里有 alt 属性。更关键的是图片分类。不同类别的图片alt 文本的写法要求完全不同。可以把页面图片分成这几类图片类型视觉作用alt 文本策略信息型图片传达内容、数据、结论用 alt 完整替代图片信息功能型图片作为按钮或链接的视觉载体alt 描述操作目标和行为装饰型图片只有视觉点缀无内容信息使用空 altalt告知辅助技术跳过文字图片图片内容本身是文字alt 直接包含文字内容复杂图片图表、流程图、示意图简短 alt 相邻位置的长文本描述装饰型图片经常被误解。如果一张图片只是为了美化页面不传达任何信息正确的做法是写成alt。这样屏幕阅读器会直接忽略它用户不会被无意义的描述打断阅读节奏。反过来如果一张信息型图片写了空 alt那视觉用户看到的信息屏幕阅读器用户就完全感知不到。另一个常见误区是把alt直接省略掉。省略 alt 和空 alt 不一样空 alt 是明确告诉辅助技术“这是装饰图片请跳过”省略 alt 会导致部分读屏软件把文件名读出来造成干扰。所以即使图片是装饰性的也应写成img srcdecorative.png alt而不是删掉属性。弄清楚这个基础后才能真正理解自动化检查的局限在哪。3. 自动化检查能做到什么不能做到什么先看主流工具。Lighthouse、axe-core、WAVE、eslint-plugin-jsx-a11y它们检查 alt 文本的基本逻辑很相似先找到所有 img 元素再看有没有 alt 属性alt 是否为空以及图片作为链接唯一内容时是否能形成可读的链接文本。这些工具能可靠捕获的典型问题包括img 缺少 alt 属性。a 标签内只有图片但没有可以朗读的文本。button 元素内只有图片没有文字。aria-label 或 alt 的值为空白字符串时导致控件无名称。用 axe 检测时这类问题通常对应image-alt、link-name、button-name等规则。比如下面这段代码任何自动化工具都会直接报错a href/product/1001 img srcproduct-thumbnail.jpg / /a因为链接内部没有任何可访问名称屏幕阅读器用户无法知道这个链接指向哪里。但工具的能力边界也在这里。自动化工具无法判断以下内容alt 是否真的描述了图片的核心含义。alt 是否和周边文字重复。图片中的文字是否完整出现在 alt 里。alt 是否适合当前上下文。图片更新后 alt 是否已经过期。功能型图片的 alt 是否写出了操作行为。这些全部是语义层面的判断需要理解图片内容、页面场景和用户需求。比如下面这段代码自动化检查会给出“通过”的结果因为它有 alt而且 alt 非空img srcchart-quarterly.png alt季度营收图 /但合格吗如果这个季度营收图想呈现的是“前三个季度持续下滑第四季度快速回升”alt 写成“季度营收图”等于什么都没说。屏幕阅读器用户只得到一个标题而不是数据背后的结论。所以更稳妥的判断是自动化检查适合做“下限控制”保证最基本的规则不破但它做不了“上限评估”评估内容是否真正有效。4. 五个典型场景检查通过但 alt 文本实际不合格这一节是全文重点。下面五个场景自动化检查全部能够通过但用户体验都存在明显问题。4.1 数据图表只有标题型 alt数据信息全部丢失这是最常见、也最严重的问题。!-- 自动化检查通过alt 存在且非空 -- img src/images/company-2024-revenue.png alt公司2024年营收图表 /屏幕阅读器用户听到的是“公司2024年营收图表”。这句话等价于给用户看了一张空白的图表轮廓却没有告诉他任何数据。图表存在的意义是让读者理解营收规模、增长趋势、关键节点。alt 文本应当替换图片来完成这个任务。一个更合格的写法img src/images/company-2024-revenue.png alt公司2024年营收达到1200万元同比增长32%其中第四季度增长最快单季度营收占全年的36%。 /如果图表信息非常复杂一两句话讲不完不要把长文本全部塞进 alt 属性。更好的方式是在图表旁边提供完整的数据表格alt 只写“2024 年营收趋势图详细数据见下方表格”。4.2 功能型图片的 alt 没有描述操作行为当图片作为链接或按钮出现时alt 应该描述“点击后会干什么”而不是描述图片长得什么样。a href/download/manual.pdf img src/images/download-icon.png alt下载图标 / /a这个例子中alt 写的是“下载图标”。屏幕阅读器用户听到“下载图标”时只知道页面有个图标不知道点击后的结果。自动化规则会检查“链接有可读名称”但不会检查名称是否正确描述行为。修复方式很简单a href/download/manual.pdf img src/images/download-icon.png alt下载产品手册 / /a同样的原则适用于按钮。如果按钮由图标和文字组成最佳方案是同时保留可见文字图片写成空 altbutton typebutton img src/images/search.svg alt / 搜索 /button这样按钮名称就是“搜索”屏幕阅读器不会把“搜索图标搜索”重复读出来。4.3 alt 与周边文字重复造成信息冗余有些团队很用功给每一张带说明的配图都写了详细 alt但没注意到图片下方已经有 figcaption 说明了同样内容。figure img srcsystem-architecture.png alt系统采用前后端分离架构前端使用 Vue后端使用 Spring Boot数据库使用 MySQL / figcaption系统采用前后端分离架构前端使用 Vue后端使用 Spring Boot数据库使用 MySQL/figcaption /figure屏幕阅读器用户会把这两段内容连续读出来听感非常糟糕。自动化工具无法识别这种语义重复。此时 alt 有两种处理方向如果 figcaption 已经完整表达了图片信息alt 设置为空。如果 alt 能补充 figcaption 没有提到的信息保留并精简 alt。figure img srcsystem-architecture.png alt三类客户端通过 API 网关接入后端服务 / figcaption系统采用前后端分离架构前端使用 Vue后端使用 Spring Boot数据库使用 MySQL/figcaption /figure原则是同一个页面中同一信息不要被无关地重复朗读。4.4 截图中的文字没有进入 alt页面业务系统经常有操作截图、错误提示截图、审核结果截图。看图的人能一眼看到错误信息但屏幕阅读器用户完全获取不到。img src/images/payment-error.png alt支付失败截图 /“支付失败截图”没有告诉用户具体为什么失败、接下来能做什么。把截图里的关键文字完整放进 alt 才是正确做法img src/images/payment-error.png alt支付失败银行返回错误原因为余额不足。页面提供重新支付和返回商城两个按钮。 /alt 不是图片标题而是图片的替代品。用户看不到图的时候alt 要尽力还原图传达的信息。4.5 alt 文本随图片更新而过期这种情况在运营类页面尤其多。活动入口图、价格说明图、通知公告图经常被替换但前端代码里的 alt 文本没有被同步更新。比如线上图片已经从“限时特惠 99 元”换成了“限时特惠 89 元”alt 还写着 99 元。自动化检查通过因为 alt 存在且非空。但视觉用户看到 89 元屏幕阅读器用户听到 99 元两边信息不一致这在涉及价格、时间、政策等关键信息时是严重事故。要解决这个问题不能只靠前端需要把 alt 更新放进内容发布流程。5. 实操从“检查通过”升级到“语义合格”自动化工具不能替代语义判断但可以用工程手段提高人工评审的效率。5.1 团队评审引入“替代体验测试”评审 alt 文本时可以做一个简单的操作把图片遮住只看 alt 文本判断用户能否理解页面信息和操作。针对每一张非装饰型图片至少问四个问题这张图片在页面里提供了什么视觉信息alt 文本是否完整地替代了这些信息alt 是否与图片周围的文字重复图片上如果有文字是否全部出现在 alt 里这四个问题全部通过alt 才算初步合格。建议把这个清单放到代码评审的模板中前端同学 MR 里附带图片 alt 清单评审人对照检查。5.2 用脚本提取所有图片生成人工审查候选列表人工一张一张点开页面找图片成本太高。可以写一个小工具在开发环境跑一遍把页面里所有图片的 src 和 alt 提取出来形成待审核清单。下面是一个使用 Playwright 的示例脚本抓取指定页面所有图片信息// 文件路径scripts/check-alt.mjs import { chromium } from playwright; const url process.env.CHECK_URL || http://localhost:3000; const browser await chromium.launch(); const page await browser.newPage(); await page.goto(url, { waitUntil: networkidle }); const images await page.$$eval(img, (imgs) imgs.map((img) ({ src: img.getAttribute(src), alt: img.getAttribute(alt), width: img.clientWidth, height: img.clientHeight, loading: img.getAttribute(loading), })) ); const noAlt images.filter((img) img.alt null); const emptyAlt images.filter((img) img.alt ); const hasAlt images.filter((img) img.alt img.alt.trim() ! ); console.log( 缺失 alt 的图片 ); console.table(noAlt); console.log( 空 alt装饰图候选); console.table(emptyAlt); console.log( 需要人工审核语义的图片 ); console.table(hasAlt); await browser.close();运行方式CHECK_URLhttp://localhost:3000 node scripts/check-alt.mjs这个脚本不是用来判断 alt 是否合格而是把候选列表整理出来。前端团队只需要审核hasAlt部分以及确认emptyAlt里的图片确实都是装饰性图片。5.3 把自动化检查加入 CI 门禁推荐在 CI 中接入 axe-core。下面是一个常见的 npm script 配置{ scripts: { a11y:audit: node scripts/a11y-audit.mjs }, devDependencies: { axe-core/playwright: ^4.9.0, playwright: ^1.45.0 } }对应的审计脚本// 文件路径scripts/a11y-audit.mjs import { chromium } from playwright; import AxeBuilder from axe-core/playwright; const urls process.env.AUDIT_URLS ? process.env.AUDIT_URLS.split(,) : [http://localhost:3000]; const browser await chromium.launch(); for (const url of urls) { const page await browser.newPage(); await page.goto(url, { waitUntil: networkidle }); const results await new AxeBuilder({ page }) .withTags([wcag2a, wcag2aa]) .analyze(); console.log(\n ${url} ); console.log(违规数量: ${results.violations.length}); for (const violation of results.violations) { console.log(- [${violation.impact}] ${violation.help}); for (const node of violation.nodes) { console.log( ${node.target.join( )}); } } if (results.violations.length 0) { process.exitCode 1; } await page.close(); } await browser.close();这段脚本会让 CI 在存在 a11y 规则违规时失败。注意它依然只是自动化层面不建议把它当作质量达标的最终证明。5.4 用无障碍树快速人工验证Chrome DevTools 的 Elements 面板里选中一个元素后可以在 Accessibility 标签中查看它的“无障碍名称”。这个名称就是屏幕阅读器用户会听到的内容。人工审核时逐个选中图片、链接、按钮检查它们的无障碍名称是否符合预期比完整打开读屏软件更快也更容易定位问题。6. 手动验证的实操方法与工具自动化检查加工程脚本能筛掉大部分问题但最终验证还是需要真实读屏环境。下面给出最简操作路径。Windows 上推荐使用 NVDA免费且开源。安装后打开浏览器用 Tab 键和非 Tab 键移动焦点听 alt 文本的朗读顺序是否符合页面逻辑。更快的做法是使用 NVDA 的图片列表功能一次列出页面所有图片直接检查每个图片的 alt。macOS 上使用 VoiceOver。按Command F5开启然后使用Control Option 左右箭头在页面元素间移动聚焦到图片时会自动朗读 alt。重点验证场景数据图表图片的 alt 是否包含具体数据结论。链接按钮图片的 alt 是否能说明操作。纯装饰图片是否被跳过。图文混排时阅读顺序是否自然。图片更新后 alt 是否与当前视觉内容一致。手动测试不需要把整站所有图片都过一遍。建议先选核心业务路径的页面比如首页、搜索列表页、详情页、下单页、支付结果页这部分体验对用户影响最大。7. 常见问题与排查思路问题现象可能原因排查方式解决方案Lighthouse 全绿但读屏用户反馈图片信息缺失自动化工具只验证 alt 存在不验证语义用 NVDA/VoiceOver 试点页面补充人工评审清单逐张审核非装饰图片img 有 alt 属性但读屏软件读出文件名alt 值为空字符串且被当成装饰图检查无障碍树中图片名称仅对真实装饰图使用alt信息型图片必须有文本链接上的图片按钮没有读出可点击信息a 标签内图片 alt 描述的是图片而非操作检查链接的可访问名称将 alt 改为描述点击行为同一段信息被读两次alt 与 figcaption 或正文重复用屏幕阅读器听完整段落精简 alt或将其设为空图表图片 alt 太长用户听不完把复杂图表所有数据都塞进 alt查看 alt 字数超过两句话图表旁放数据表格alt 只写结论图片价格信息与 alt 不一致运营更新图片后未同步 alt抽查运营位图片把 alt 更新纳入内容发布验收条件8. 最佳实践与工程建议8.1 明确 alt 文本的负责人alt 文本应该由最理解图片内容的人提供底稿。运营传的图片运营要写清楚图片信息设计师设计的数据图表设计师要提供数据结论前端负责把它落到代码里并做语义验证。不要把这个任务默认丢给前端因为在大多数团队里前端并不清楚运营图片背后想传递的完整信息。8.2 把 alt 更新纳入图片变更流程很多团队有“图片替换”流程但没有“alt 替换”流程。建议在内容发布检查单中加一条图片替换时必须同步检查 alt 文本是否过期。如果图片涉及价格、时间、规则等关键信息这条检查不能跳过。8.3 代码规范中约束 alt 写法如果项目中使用了 JSX可以通过 eslint-plugin-jsx-a11y 在代码层面强制要求基础规则npm install eslint-plugin-jsx-a11y --save-dev在 ESLint 配置中启用alt-text规则{ plugins: [jsx-a11y], rules: { jsx-a11y/alt-text: [error, { img: [Image], object: [Object], area: [Area], input[type\image\]: [InputImage] }] } }这能保证代码提交时img、object、area、input[typeimage] 都有 alt 属性但同样解决不了语义问题。8.4 不要用空 alt 逃避检查有些团队为了通过 ESLint 或 axe 检查把不确认怎么写的 alt 统一设成空字符串。这是非常危险的做法。空 alt 只有在图片确实是装饰性时才是正确的把信息型图片标成空 alt等于让屏幕阅读器用户直接丢失这部分内容。8.5 复杂图片优先使用“短描述 数据表格”不要把复杂图表的全部内容塞进 alt。更好的做法是在图片下方放一个 summary 段落或表格来承载详细数据alt 只写简洁结论。这样屏幕阅读器用户不会被大段文字打断也能按需获取详情。8.6 做无障碍回归清单时包含 alt 上下文建议把 alt 评审从代码审查中独立出来作为产品验收的一部分。每次涉及图片新增、替换、页面结构调整时都跑一遍 5.1 节中的四个问题。时间长了团队会形成一套自己的 alt 质量标准。9. 总结与后续学习方向自动化检查是安全网不是合格证。它保证了 alt 属性存在、基础规则不破却无法判断图片的语义信息是否被完整传递。真正合格的 alt 文本需要结合图片内容、页面上下文、用户场景来判断这必须有人工参与。建议你从今天开始做三件事用 Playwright 脚本把项目核心页面的图片和 alt 提取出来建立一份“待人工审核”清单。在代码评审模板中加入 alt 四问检查强制非装饰图片走人工语义评审。挑一个核心业务页面用 NVDA 或 VoiceOver 完整走一遍亲身体会 alt 文本在真实读屏中的表现。如果想让团队长期受益可以继续深入研究 WCAG 2.1 的 1.1.1 非文本内容标准以及更复杂的 SVG 图标无障碍方案、复杂图表数据表格设计。这些内容都是对 alt 文本这个话题的延伸也是从“通过检查”走向“真正可用”的下一站。