公司动态

网页图片的无障碍实战:alt 到底怎么写,屏幕阅读器里那些图是什么样的

📅 2026/7/14 18:16:07
网页图片的无障碍实战:alt 到底怎么写,屏幕阅读器里那些图是什么样的
做前端第八年我第一次认真戴上耳机、关掉屏幕、用 VoiceOver 从头到尾听完自己做的页面是被一个客服工单逼的。有个视障用户投诉说我们商品列表页根本没法用每张图都念一串乱码。我打开一看——好家伙产品图的 alt 全是后端拼的文件名altIMG_20240517_093412_v2_final_final.jpg。屏幕阅读器一板一眼地把这串东西读了出来。那一刻我意识到我过去写的无数个alt属性基本都是应付 lint 规则用的从没考虑过它真正被念出来是什么感受。这篇就把我这两年趟出来的图片可访问性经验倒一倒。不讲大道理全是能直接抄进项目的判断和代码。先分清这张图到底是干嘛的所有关于 alt 的纠结本质都是一个问题没想清楚——这张图在页面里承担的是信息还是装饰。这两类的处理方式是相反的混了就出错。信息性图片指的是图片本身携带内容去掉它信息就缺了一块。产品照片、图表、说明性截图、有文字的 banner都算。这类必须写有意义的 alt。装饰性图片指的是它纯粹是视觉点缀去掉它内容一点不少。分隔线、圆角背景纹理、纯氛围的配图、和旁边文字重复的图标都算。这类必须显式声明为空让屏幕阅读器直接跳过。关键的坑在装饰这一侧。很多人以为装饰图不写 alt 就行了错。看这段!-- 灾难写法屏幕阅读器会念出 URL 或文件名 --imgsrc/assets/divider-gold.png!-- 正确空 alt屏幕阅读器完全跳过 --imgsrc/assets/divider-gold.pngaltimg没有 alt 属性时多数屏幕阅读器会退而去读src的文件名当替代文本于是用户听到一串divider-gold-png。而alt注意是空字符串中间不能有空格是一个明确信号这张图无内容价值别念。这俩差了十万八千里我 review 代码现在第一件事就是抓没有 alt 属性的img。如果你更想表达语义上这是个装饰角色也可以用rolepresentation或rolenone效果和空 alt 类似都是把元素从无障碍树里剔掉imgsrc/bg-texture.pngaltrolepresentation不过实测下来alt兼容性最稳能覆盖到就够了role是锦上添花。信息性图片的 alt写内容不写外观好装饰的搞定了难的是信息图 alt 怎么写。我总结的一条准则替代文本要传达图片承载的信息和功能而不是描述像素长什么样。举个例子同一张红色感叹号图标 库存不足的图!-- 描述外观没用 --imgsrc/icon-warning.svgalt红色三角形里有个感叹号!-- 传达信息对了 --imgsrc/icon-warning.svgalt库存不足用户不需要知道那是三角形还是圆形、红色还是橙色——那是给视觉设计看的。他需要知道的是库存不足这件事。再进阶一层alt 要看上下文。同一张爱因斯坦的照片放在人物传记页和放在经典打印海报电商页alt 该完全不同。前者可能是阿尔伯特·爱因斯坦晚年肖像后者更该是爱因斯坦吐舌头黑白海报A2 尺寸因为在购物场景里用户关心的是这个商品是什么。同一张图没有标准答案脱离上下文谈 alt 都是耍流氓。几条我常用的实操细节alt 别加图片“” 一张……的照片这种前缀。屏幕阅读器碰到img本来就会先播报图像你再写图片就成了图像 图片 XXX啰嗦。如果图片是个链接或按钮里唯一的内容alt 必须描述这个操作会去哪/做什么而不是描述图长啥样。比如站标 logo 通常链到首页写alt返回首页比alt公司logo有用得多。图里有文字的话alt 一般要把关键文字抄进去尤其是营销图上的价格、优惠信息。这些文字对视觉用户可见对视障用户就凭空消失了。长度别失控。一句话讲清就行通常别超过一行。真需要长描述的复杂图表用下面讲的aria-describedby。复杂图表和信息图一句 alt 装不下数据可视化是重灾区。一张趋势折线图你 alt 写2024 年销售趋势图等于没写——用户知道有张图但图里说了啥一无所知。处理思路有两层。第一层alt 给个概括结论。第二层用aria-describedby挂一段详细的文字替代把图里的数据讲清楚。figureimgsrc/sales-2024.svgalt2024 年季度销售额呈上升趋势aria-describedbysales-descfigcaptionidsales-descQ1 销售额 120 万元Q2 增至 165 万元Q3 达到 210 万元 Q4 冲到 280 万元。全年环比持续增长Q4 增幅最大 较 Q3 提升约 33%。/figcaption/figure这里我把详细描述放进了可见的figcaption一举两得视觉用户也能看到数据摘要视障用户通过aria-describedby关联读到。aria-describedby的值是目标元素的 id屏幕阅读器读完 alt 会接着读这段。早年有个longdesc属性专门干这事但它是外链一个描述页面的浏览器支持烂、维护也烦现在基本淘汰了。aria-describedby加可见 figcaption 是我现在的默认解法。如果你不想让描述在视觉上显示可以放进一个视觉隐藏但屏幕阅读器可读的容器下面有.sr-only的写法但我更倾向让所有人都看到数据摘要反正对谁都有好处。信息图infographic同理那种一大张塞满流程和数字的图最好在旁边或下方提供等价的结构化文本/列表别指望一个 alt 交代清楚。SVG 图标的可访问性比 img 麻烦内联 SVG 现在满天飞但它不是img没有 alt 属性处理方式单独一套。而且不同屏幕阅读器对 SVG 的支持参差不齐这块坑最多。先分场景。纯装饰的 SVG 图标旁边已经有文字标签的那种直接aria-hiddentrue藏掉buttonsvgaria-hiddentruefocusablefalsewidth16height16usehref#icon-cart/use/svg加入购物车/buttonaria-hiddentrue把 SVG 从无障碍树移除用户只会听到按钮的文字加入购物车。那个focusablefalse是给老 IE/Edge 擦屁股的——某些旧版本里 SVG 会意外可聚焦Tab 键会卡在上面加上这个防患。现在能不能省看你兼容目标我一般还是留着一个属性的事。承载信息的 SVG比如一个只有图标没有文字的图标按钮必须补语义。两种主流写法!-- 方式一aria-label 直接给可访问名 --buttonaria-label搜索svgaria-hiddentruefocusablefalseusehref#icon-search//svg/button!-- 方式二SVG 内部用 title role --svgroleimgaria-labelledbysearch-titlewidth20height20titleidsearch-title搜索/titleusehref#icon-search//svg方式一是我用得最多的图标 SVG 一律aria-hidden把可访问名交给外层的button/a用aria-label提供。逻辑清晰也不受 SVG 屏幕阅读器兼容性折腾。方式二用 SVG 内部的title加roleimg加aria-labelledby。注意光有title不够可靠SafariVoiceOver 有时不认所以要显式roleimg加aria-labelledby指向 title 的 id把三件套配齐兼容性才稳。SVG 里还有个desc可以放更长的描述用得少复杂图形才需要。顺便提一句use href#...引用 symbol 的写法图标本体的 symbol 定义里也别塞 title容易和使用处的语义打架语义统一在使用处给。CSS 背景图无障碍树里根本不存在这个概念很多人没意识到用background-image铺的图屏幕阅读器完全感知不到无障碍树里它不存在。这既是坑也是特性。如果你拿背景图去放装饰性内容——纹理、渐变、氛围图——那太好了天生就被无障碍忽略你啥也不用管这正是我们想要的。但如果你偷懒把信息性内容做成了背景图我见过有人把限时五折的促销文字直接切成背景图铺上去那视障用户就彻底丢失了这个信息因为背景图没有任何替代文本机制。这种情况要么改回img alt要么在那个元素上补 ARIAdivclasshero-bannerroleimgaria-label限时五折促销仅剩 3 天/div给背景图容器加roleimg加aria-label相当于手动把它塞回无障碍树。但说实话这是补救能用真img就用真的语义天然、SEO 也友好。真机实测VoiceOver 和 NVDA 会打架代码写得再漂亮不上真机听一遍都是纸上谈兵。我踩过最多的亏就是看起来 ARIA 都对实际读出来不对。几个实测经验macOS VoiceOverCmdF5 开启CtrlOption右方向键逐项走对 SVGtitle的支持时好时坏尤其配 Safari。前面说的roleimg加aria-labelledby三件套就是为了绕它。VoiceOver 读img会先播图像再读 alt。Windows NVDA免费配 Firefox 或 Chrome 测整体对 ARIA 支持更规矩但它和浏览器的组合会影响结果——NVDAFirefox 和 NVDAChrome 对同一段aria-describedby的播报时机能不一样。所以我至少测 VoiceOver/Safari NVDA/Firefox 两组。一个特别容易翻车的点aria-label和元素内的可见文字同时存在时aria-label会覆盖掉可见文字屏幕阅读器只念 aria-label。我见过有人给一个加入购物车按钮加了aria-label购物车结果视障用户听到的是购物车把动作词加入给吞了。所以按钮如果本身有文字多半根本不需要 aria-label别画蛇添足。还有个免费的低成本自查手段装个 axe DevTools 或用 Lighthouse 的 accessibility 审计跑一遍能自动抓出缺 alt、对比度不足这类硬伤。但记住自动化工具只能查约 30%-40% 的问题alt 写得对不对、有没有意义这种它判断不了最后还得靠人戴上耳机真听。一段能到处用的视觉隐藏工具类最后送个高频工具。有时你想给屏幕阅读器提供额外文字比如图标按钮的说明又不想视觉上显示别用display:none或visibility:hidden——那俩会把内容从无障碍树也一起干掉屏幕阅读器读不到。要用这个经典的.sr-only.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}ahref/cartsvgaria-hiddentrueusehref#icon-cart//svgspanclasssr-only购物车3 件商品/span/a它把元素缩到 1px 挤出视口外、裁剪掉视觉上不可见但仍留在无障碍树里屏幕阅读器照读。这一个类能解决大半想补语义又不想动视觉的场景。说点诚实的边界写到这儿得泼点冷水。图片可访问性没有银弹alt的正确高度依赖上下文和业务判断很多时候没有唯一答案只有更合适的答案——这活儿本质上是内容工作不是纯技术活指望某个规则或工具帮你自动生成好 alt目前都不现实。自动生成的描述往往只描述像素、抓不住页面语境还得人来兜底改。另外我这套经验主要覆盖屏幕阅读器这一类用户可访问性远不止于此——低视力放大、色盲对比度、键盘导航、认知障碍每一块都是深水区我也还在学。SVG 那部分的兼容性尤其是流沙浏览器和读屏软件版本一变可能就有出入别把我上面写的当成永久真理上你自己的目标环境实测才算数。真要开始改我的建议是别追求一步到位。先跑个 axe 把没有 alt 的图全揪出来堵上这是最低标准也是收益最高的一步再逐步区分装饰与信息、给关键图表补文字替代。哪怕只做到第一步对那些戴着耳机听你页面的用户来说已经是天壤之别了。图片是网页里最容易被无障碍遗忘的角落但它其实是最好补的一块——很多时候就差一个认真写的alt。