1. 为什么传统购物网站对视障用户是一堵墙
先说一个我自己的经历。几年前我帮某电商团队做无障碍排查,用读屏软件打开当时的主站首页,整个页面在语音里循环播放了将近四十分钟才勉强读完前三个屏。导航菜单没有层级、商品卡片缺少替代文本、价格信息被拆成碎片、按钮用图片实现却没有任何可读名称——这些在视觉上完全看不出来的问题,对使用屏幕阅读器的用户来说,就是一座无法翻越的高墙。
盲人用户在网购时会遇到哪些障碍,我们得先弄清楚才能谈解决方案。屏幕阅读器(比如常见的 NVDA、VoiceOver、TalkBack)依赖的是页面背后的语义结构,而不是像素层面的视觉效果。如果开发者在写代码时只想着“看起来怎样”,没有同步考虑“读出来是什么”,那再好看的商品页也毫无意义。具体来说,问题通常集中在这几个地方:
- 图片没有替代文本。商品图纯粹是装饰,读屏软件只能念出“图片”两个字,用户完全不知道这是什么商品。
- 交互组件没有可访问名称。一个“加入购物车”按钮如果只放了一个购物车图标,且没有通过可访问名称(accessible name)说明用途,读屏用户听到的可能是“按钮”或者“未命名”。
- 信息顺序错乱。视觉上你可能通过颜色、字号、布局来传递主次关系,但读屏软件只能按照 DOM 顺序线性朗读。一旦布局与代码顺序不一致,用户听到的信息顺序就是灾难。
- 表单不关联标签。搜索框、收货地址输入框、支付信息填写框没有对应的 label 元素,用户根本不知道当前光标落在哪个字段上,只能靠猜。
- 验证码无法绕过。图文验证码对视障用户几乎是无解的,如果没有替代方案,购物流程在这一步就彻底中断。
正是这些问题的存在,才有了 DinamicX 这类专注无障碍在线购物体验的解决方案。它的核心思路不是“另造一套系统”,而是在既有电商平台之上,通过语义化重构、可访问组件抽象和跨端适配,让原本无法被读屏软件理解的页面变成结构清晰、可操作的信息流。说人话就是:不改变你看到的界面,但改变读屏用户听到和操作的逻辑。
文章中提到的“让盲人也能在线购物”,本质上不是做慈善式的辅助,而是把信息无障碍(Accessibility)作为一条硬性的产品质量指标来对待。这背后有一个常被忽视的事实:无障碍改造最终受益的是所有用户。比如按钮的可点击区域变大、对比度提高、导航层级变清晰,对视力正常但手抖、屏幕反光、或者临时一只手抱娃的用户同样是体验提升。
我在这篇文章里会把 DinamicX 拆开来讲:它帮的是哪一层的问题,核心机制是怎么运作的,一条完整购物流程在无障碍环境下是怎么走通的,以及真正的测试应该怎么做。目标是让做产品、做研发、做设计的读者都能从这里拿到可直接参考的思路,而不是停留在“我们要关爱视障人群”这种口号层面。
2. 无障碍购物体验的底层逻辑:语义结构就是骨架
要理解 DinamicX 这样的方案为什么有效,先得搞清楚屏幕阅读器到底是怎么“看”网页的。
2.1 从 DOM 到无障碍树:读屏软件的信息来源
浏览器会把页面解析成 DOM 树,同时还会生成一棵单独的无障碍树(Accessibility Tree)。这棵树包含了页面中所有对辅助技术可见的信息:每个元素的角色(role)、名称(name)、状态(state)和值(value)。屏幕阅读器朗读的、用户通过键盘操作的,全部来自于这棵树,而不是视觉上的渲染结果。
举个例子。你在页面上放了一个自定义的下拉筛选框,视觉效果是一个精致的圆角控件,但它的底层可能是若干个 div 拼出来的。在无障碍树里,它可能被识别成一组普通文本,没有“下拉框”这个角色,也没有展开/收起状态。这时候读屏用户听到的就不是“品牌筛选,下拉框,已折叠”,而是毫无意义的文字串。DinamicX 做的事,首先是纠正这一层的语义问题——给控件正确命名、声明角色、描述状态,确保无障碍树里呈现的信息是结构化的。
这就像装修房子:视觉设计是软装,怎么好看怎么摆;无障碍设计是水电管线,你看不见它,但住进去舒不舒服全看它走得好不好。很多团队在做页面时只盯着软装,等到要接读屏才发现管线全堵死了。
2.2 DinamicX 的实际解法:可访问组件的抽象与复用
DinamicX 不是某一种 API 或某个工具库,它更像一套专门为无障碍购物场景定制的前端方案集合。核心可以拆成三块:
- 语义化组件库。所有常用的电商组件都被重新实现了一遍,确保它们具备正确的 WAI-ARIA 属性。商品卡片、价格区间、筛选器、排序按钮、购物车数量调整、地址选择器、支付方式单选等,每个组件在无障碍树里的角色和命名都是经过刻意设计的。
- 键盘操作全覆盖。读屏用户通常不用鼠标,全部靠键盘 Tab 键、方向键、空格键、回车键来操作。DinamicX 为每个交互元素定义了清晰的焦点顺序(focus order),并且保证所有功能都可以只通过键盘完成。最容易被忽略的是轮播图和抽屉组件——鼠标用户可以随意点击,但键盘用户经常被困在里面出不来,焦点管理不到位就会“焦点落穴”。
- 实时状态播报。比如加入购物车成功、优惠券已领取、库存不足、订单提交失败,这些反馈在视觉上可能是绿色的对勾提示,一闪而过。读屏用户需要的是通过“aria-live”区域自动播报。DinamicX 会把这些状态变化注入到页面的 live region 中,确保用户即使没有看到提示,也能第一时间知道操作结果。
这三个层面缺一不可。只有语义没有键盘支持,用户能读到但操作不了;只有键盘支持没有状态播报,用户操作了但不知道成没成功;只有播报没有语义,用户听到的信息顺序和结构依然是乱的。
2.3 为什么大部分电商项目的无障碍做不好
聊到这里,我想针对很多团队“做了无障碍但效果仍然很差”的现象说两句。最常见的原因有三个:
第一,把无障碍当成安装插件一样一次性搞定。实际上面临的是一个持续迭代的过程,每次新增组件、改版页面都可能引入新的障碍,需要有一整套规范和检测机制跟着走。
第二,只做自动化检测,不做真人实测。自动化工具能查出来项目里有没有 alt 属性、有没有 label 关联,但它查不出一个真实的读屏用户从头到尾走一遍下单流程时,会不会在某个交互上卡住。语义正确不等于体验顺畅,这个差距只能通过人工走查来发现。
第三,把无障碍当成残缺视图的补救。很多人觉得“这个页面功能太多,盲人用不到,我们单独做个简化版或者直接走客服电话就行了”,这种思路实际上剥夺了视障用户自主选择的权利。DinamicX 的出发点完全不同:它要求主流程本身是可达的,而不是在旁边搭一条“特殊通道”。这样就不存在信息不一致、功能缺失、体验降级的问题。
3. 选品与搜索环节怎么做:从“能看到”变成“能找到”
购物体验的第一步往往是搜索和浏览。对视力正常的用户来说,这是一瞬间的事;对读屏用户来说,这背后藏着大量细节。
3.1 搜索框的无障碍实践
搜索框看起来是最简单的元素,反而是很多站点栽跟头的地方。我见过太多搜索框,placeholder 写得清清楚楚“搜索商品”,但输入框本身没有关联 label,读屏用户把光标移进去,听到的只有一个“编辑文本”,完全不知道这个输入框是干嘛用的。
正确的做法是显式地使用 label 元素。不要依赖 placeholder——它在无障碍环境里的表现很不稳定,而且会在输入内容后被遮挡,等于信息又消失了。从 DinamicX 的角度,它还要求搜索框具备完整的建议下拉列表支持:当用户输入关键词时,建议项应该及时通过自动播报的方式呈现,用户可以用上下方向键选择建议,按回车确认搜索,全程焦点都不能丢失。
关键词联想还有一个容易被忽略的细节:错误提示。当用户输入的关键词没有匹配结果,页面上不能只显示一个“抱歉,找不到相关商品”。读屏用户需要的是一条明确的语音提示,说明这次搜索失败了,以及可以如何调整(比如换个词或者查看热门搜索)。这类反馈如果不做进 live region,用户会以为页面卡死了,反复按回车触发搜索,体验非常糟糕。
3.2 商品瀑布流的读屏顺序改造
电商首页和搜索结果页基本都爱用瀑布流布局。视觉上,两列甚至三列的商品卡片交错排列,非常紧凑。但在 DOM 顺序里,商品的实际排列可能是先左列第一个,再右列第一个,再左列第二个。读屏用户沿着 DOM 顺序读下去,听到的商品顺序在视觉上是跳跃的。这倒还不是最致命的,最致命的是商品卡片本身的可读性。
一张标准商品卡片里通常有:商品主图、品牌名、商品名称、促销标签、价格、原价划线价、评价数、加购按钮。如果开发时没有好好规划,读屏用户听到的可能是“图片、图片、图片、文字、文字、按钮”,或者价格被打散成“数字六十九、数字点、数字九”,更糟的是促销标签的替代文本居然是“双十一狂欢价”这种毫无信息量的表述。
DinamicX 的做法是给每张商品卡片定义统一的朗读模板,基本长这样:商品名称、品牌、价格、促销信息、评价数、操作按钮。这样的顺序符合用户做购买决策的心理模型——先知道是什么,再看牌子,再关心价格,最后决定操作。卡片里的次要装饰元素(比如背景纹理、点缀小图标)直接在无障碍树里隐藏,因为读出来只会产生干扰。
同时,列表页需要支持两种浏览模式:一种是浏览模式,用户逐张卡片听下去,快速扫货;另一种是交互模式,用方向键在卡片之间快速跳转。这两种模式的切换要让用户自己掌控,并且要有明确的状态提示——当前处于什么模式、怎么切换,都不能让用户猜。
3.3 筛选和排序:被严重低估的高频操作
筛选和排序在购物流程里属于高频操作,但很多团队把它做成了“只有鼠标用户才配用”的功能。自定义下拉框、拖拽滑块、多级联动菜单,视觉上很炫,到了键盘和读屏环境下立刻失控。
先说筛选框。标准原生 select 是最稳妥的选择,它的键盘操作和朗读语义是浏览器天然支持的,几乎不用额外开发成本。但电商场景里的筛选条件往往比较复杂,比如多选品牌、价格区间、尺码范围,原生控件确实有局限。如果必须自定义实现,就得保证每个筛选项都有正确的 checkbox 角色、选中状态能被实时播报、筛选结果数量变化有反馈。
再谈价格区间。拖拽双滑块是视觉效果最好的方案,但对键盘用户来说是灾难。一个合格的无障碍实现必须同时提供精确输入的方式——两个数字输入框,或者用加号减号调整。这个替代路径不能藏得太深,最好跟滑块放在同一个操作区域。
排序也是同样道理。按销量、按价格、按上架时间,这些看起来只是几个链接的事,但如果你用了点击后动态刷新的交互方式,且没有把结果变化进行播报,用户点击排序后听到的还是旧列表的内容,就会以为排序功能坏了。正确做法是在排序变化时,把结果数量和新排序方式播报出来,让用户明确感知到“页面已经更新了”。
4. 从加购到下单:交易链路里那些必须守住的细节
如果说搜索浏览是“看得到”的问题,那么从加入购物车到最终支付成功,就是“做得到”的问题。这个环节里的每一步,都在考验无障碍实施的细腻程度。
4.1 商品详情页:信息获取与购买决策的完整性
商品详情页是购物决策的最核心页面,也是最容易出现无障碍断层的地方。一个合格的商品详情页,至少要在无障碍树里呈现出这些信息:商品名称、价格(且要区分现价和原价)、规格参数、库存状态、服务承诺(七天无理由等)、用户评价摘要。这些信息不能散落在图片切片、折叠面板、Tab 切换里而不做结构梳理。
规格选择是一大难点。比如买衣服要选颜色、尺码,视觉上可能是并排的色块按钮。如果这些按钮没有正确的可访问名称,读屏用户听到的可能是“按钮、按钮、按钮”,完全不知道哪个对应哪个颜色。更麻烦的是,某些颜色还存在缺货状态,光靠颜色深浅来区分是非视觉用户无法理解的。
必须为每个规格选项提供完整命名,例如“藏青色,M码,有货”或“藏青色,S码,缺货”。选中的规格状态也要能够被播报,用户需要知道当前选择了什么,以及这个组合对应的价格是否发生了变化。库存紧张、只剩最后几件这类提示,同样不能只靠视觉上的红色角标,要通过 live region 告知用户。
价格信息要注意避免歧义。很多页面上标着“¥299”,如果价格碎片被分离(比如人民币符号和数字分布在不同的 DOM 节点里),读屏可能把它读成“二百九十九”甚至“二九九”,更麻烦的是如果旁边还有划线原价“¥599”,用户听到的可能是一串没有逻辑关系的数字。DinamicX 的做法是给价格区域一个统一的 aria-label,直接写清楚“价格二百九十九元,原价五百九十九元,折扣四九折”,把关系和对比一次说清楚。
4.2 凑单、满减与购物车操作的信息密度控制
购物车页面的核心操作是:调整数量、删除商品、选择优惠、查看结算金额。这几件事背后有一个共同难点——信息密度太大,读屏用户在一个页面里要同时接收和操作系统反馈。
数量加减按钮的坑在于重复朗读。很多购物车页面里,每件商品都有三个按钮:减号、数量数字、加号。如果按钮名称写得不够清晰,读屏用户听到的可能是“减号、按钮、二、按钮、加号、按钮”,完全不知道这三个按钮属于哪件商品。正确做法是给每个按钮加上商品限定,比如“减少商品‘纯棉T恤’数量,当前二件”,这样即便在读屏的线性朗读下,信息也能正确关联。
优惠券和满减的玩法对视觉用户来说已经很烧脑了,对读屏用户更是如此。满三百减五十、两件八折、跨店满减,这种规则在无障碍环境下必须被简化为可理解的文本。页面不能只显示“已选优惠:满减”,要具体说明“当前购物车已满三百元,可以使用满三百减五十优惠券,当前已达到门槛”。达不到满减门槛时,也要明确提示差多少钱才可以享受优惠,否则用户完全不知道下一步该怎么凑单。
结算金额区域还会涉及一个常被忽略的问题:金额变化是否播报。当你从购物车删掉一件商品,或者调整数量,结算区的总价变了。视觉用户能直接看到变化,但读屏用户如果不把焦点移过去,根本无从知晓。合适的方法是给结算区设置 live region,金额变化时自动播报“结算金额更新为二百三十五元”,省去用户手动查找的负担。
4.3 地址填写、支付选择与防误操作的设计
下单环节的表单强度和复杂度陡然上升,这对信息无障碍的要求是最高的。收货人姓名、手机号、省市区、详细地址、支付方式,每一步都不能出错,而每一步在无障碍环境下都潜藏着陷阱。
地址选择器是重灾区。不少电商的省市区三级联动使用自定义弹窗,弹层打开后,焦点没有移入弹窗;在弹窗里选择完省份后,市区数据刷新但焦点没有归位。这些问题的结果就是:用户选完省市,读屏还在念旧的内容,焦点落在弹窗外的页面上,后面想继续操作却找不到方向。
正确的弹窗无障碍规程是:打开弹窗时焦点自动移入并聚焦到第一个可操作元素;弹窗关闭时焦点归还给触发它的按钮;弹窗里的每个选项都有清晰的朗读文本和选中状态;省市区联动数据更新时,播报当前已选中的内容,同时焦点保持在用户可控的位置。
支付方式选择看起来只是几个单选框,但往往藏着一个细节:如果某个支付方式在视觉上通过图标展示,读屏用户听到的可能是“单选按钮、未选中、图标”,根本不知道这是微信支付还是其他什么方式。必须为每个支付选项提供完整的可访问名称,比如“支付宝,推荐使用”“银行卡支付,支持储蓄卡和信用卡”。
确认订单页面的“提交订单”按钮,是所有购物流程里最不允许出错的元素。有些页面在用户点击提交后会弹出二次确认,读屏用户如果没听到任何确认提示,就可能在误触中把单子提交了。因此提交按钮的操作反馈必须做到三级:点击时立即播报“正在提交订单”;提交成功后播报“订单提交成功,订单号xxxx”;失败时播报具体的失败原因,而不是只显示一个红色错误提示条。
5. 支付环节的无障碍缺口:验证码与其他“安全墙”
下单走到最后一步,往往被一道“安全墙”拦住——验证码。这是盲人网购断点率最高的一环,也是平台最纠结的地方。
5.1 图形验证码的无障碍替代方案
图形验证码的设计初衷是挡住机器,但它同时把真实用户也挡在了门外。一个图片里画着歪歪扭扭的字母数字,视觉正常的人都要眯着眼看半天,想通过语音让读屏用户进行描述,既不安全也不现实。
合规且可用的替代方案有几条路:
- 短信验证码。这是目前最成熟、用得最广的方案。手机号本身就是实名信息的一部分,发送一次性短信验证码既安全又便捷。
- 语音验证码。基于是电话通道播报一长串数字,适合短信接收不到的场景,但交互成本稍高一些。
- 风险分级机制。对于风险评分较低的用户,直接跳过验证码;只有在设备环境异常或行为特征可疑时才出题验证。这是一种体验和安全的平衡艺术,需要后台策略的配合。
DinamicX 在实际落地时对验证码区域的处理是:所有验证码的图片必须同时提供音频替代提示;如果验证码输入有误,错误提示要说明“验证码错误,已自动刷新,请重新输入”,而不是只说“验证码错误”。自动刷新这一点很重要,很多用户会因为旧的验证码失效而反复输入失败,却不知道验证码图片已经换了。
5.2 表单验证错误的口语化播报
表单验证通常是盲人用户在支付环节遇到的另一个高发痛点。页面上的收货地址少填了门牌号、手机号少了一位,视觉用户能看到红框提示,读屏用户如果只是听到“提交失败”,一样不知道是哪里出了问题。
做无障碍的表单验证,有几个轮子必须重新造:
- 每个输入框的 label 必须与错误信息联动。当验证失败时,不但要在输入框下方显示错误文本,还要把这个文本关联到输入框的 aria-describedby 上,读屏用户聚焦输入框时能听到错误的完整描述。
- 错误提示必须口语化,例如“请输入完整的手机号码,需要十一位数字”“详细地址不能为空,请补充门牌号信息”。干巴巴的“格式不正确”对于普通用户来说都难以定位问题,更不用说读屏用户了。
- 验证的整体反馈需要汇总。提交失败时,最好有一个页面顶部的错误摘要区,把所有出错字段集中播报一遍,让用户对整个表单的状态有整体认知。如果只逐个字段播报,用户可能要来回切换焦点很多次才能把所有错误都找齐。
5.3 支付结果页的最终确认
支付完成后,用户看到的不应该是一个只有“支付成功”四个字、加一个巨大对勾的静态页面。至少在无障碍层面,这个页面还需要提供:订单金额、支付方式、预计送达时间,以及后续订单状态变更的提醒方式。很多用户支付完会习惯性地关掉页面,如果支付结果页没有把“订单号、金额、售后入口”这些信息播报清楚,用户事后翻遍短信也找不到订单入口。
我在一些项目里实测过,支付结果页如果不做任何无障碍处理,读屏用户听到的内容大致是:“图标、支付成功、图片、按钮”。这样一个页面对他们来说几乎等于没有信息。正确的方式是提供一段完整的朗读文本,把结果讲清楚,例如:“支付成功,订单号123456789,实付金额二百九十九元,预计三日内送达。页面下方有查看订单和联系客服按钮。”
6. 无障碍购物体验的隐藏成本与风险:不只是“加几个标签”
很多人以为无障碍改造无非就是加几个 aria 属性的事,真正深入做的人才知道,这是一项需要全局共识的系统工程。做不好不仅浪费人力物力,还可能带来新的安全问题。
6.1 开发中的优先级排序与团队协作
无障碍体验做得好不好,很大程度取决于团队在项目启动时的优先级安排。如果等到页面已经上线再去补,每一步都要在已有的复杂结构里“打补丁”,成本是前置设计时的数倍,而且效果往往不尽如人意。
正确的方式是从需求评审开始就把无障碍列为验收标准之一。设计师在设计稿阶段就要考虑焦点顺序、对比度、交互状态提示;开发在代码评审时就要检查可访问名称是否完整、键盘操作是否覆盖;测试在用例设计时必须包含读屏走查用例。DinamicX 这类方案提供的意义,正是在于把这些约束在一开始就嵌入到组件库里,让团队不用每次从零开始考虑“这个按钮该叫什么名字”。
真正有效的团队协作方式,是建立一个“无障碍组件清单”。每个组件对应一份文档,写清楚它在读屏环境下的朗读文本是什么、键盘操作有哪些、焦点行为如何流转。开发新页面时,先比对该清单,缺什么补什么。这样就不容易因为某个开发者的个人理解而出现标准漂移。
6.2 无障碍改造带来的信息安全隐患
无障碍功能本身是帮助用户使用的,但如果实现不当,也可能变成隐私泄露的通道。live region 播报是一个典型例子——如果开发者把不该自动播报的敏感信息(比如用户手机号、支付账号后几位)放进了 live region,旁边的人可能通过语音就听到了。动态播报的信息级别需要慎之又慎,不是所有状态变化都适合自动播报。
另一个风险点是焦点顺序。合理的焦点顺序会让操作流程顺畅,但如果焦点顺序有漏洞,用户可能通过 Tab 键进入一个视觉上完全隐藏的元素(比如一个仍然响应键盘事件的无样式弹出层),甚至可能触发未预期的弹窗。开发时要注意:所有可聚焦元素必须具有视觉焦点样式,同时隐藏元素不能保留键盘可操作性,否则读屏用户和键盘用户都会陷入不安全的交互路径。此外,自定义控件如果角色声明错误(把按钮声明成链接),辅助技术就无法按照正确的交互方式去操作它。
归根结底,无障碍改造中“对的信息给对的人”这件事需要仔细权衡。面向所有用户的自动播报内容要做到脱敏处理,而可感知的信息越精确、越清晰,用户就越不需要通过试错来理解页面的结构。
7. 实测链路与验收清单:如何验证盲人用户真的能买成
前面讲了这么多理论和实现细节,现在聊一个务实的问题:怎么验证这套方案真的有效?自动化检测工具能告诉你页面有没有 alt、有没有 label、颜色对比度是否达标,但真正要确认“用户能顺利买完一单”,必须靠人走查和真人实测。
7.1 用读屏软件走完一条完整购物流程
我自己常用的验证方法是准备四台环境:电脑上的 NVDA 配 Chrome、电脑上的 VoiceOver 配 Safari、手机上的 VoiceOver 配 Safari、手机上的 TalkBack 配 Chrome。这四种组合覆盖面比较广,基本能代表大部分读屏用户的实际使用环境。
跑测时不能只做“页面可达性测试”,要模拟真实购物行为。我会固定一条完整的单人匿名测试场景:搜索一件商品 → 筛选品牌和价格区间 → 查看商品详情 → 选择规格 → 加购 → 修改数量 → 使用优惠券 → 填写地址 → 选择支付方式 → 提交订单 → 完成支付。每个环节记录三个指标:完成耗时、出错次数、卡点位置。卡点指的是用户完全不知道如何继续操作、或者进行了错误操作且得不到有效反馈的地方。
这套走查跑完,通常会暴露出许多自动化工具捕捉不到的精细问题。举一个我在某项目里遇到的例子:一个折叠面板里的“更多商品信息”,键盘用户可以 Tab 进去,按 Enter 展开,焦点也能进入展开后的内容。表面看功能是通的,但 NVDA 用户在实际操作时,无论如何都无法发现这个面板是可交互的——因为面板的触发按钮在无障碍树里的名称是“按钮”,没有任何文本提示它是“更多信息展开按钮”。自动化工具完全检测不到这个问题,因为它只看得到属性和结构,看不到用户在真实语境下的理解和判断。
7.2 真实用户招募:找对人比测多少次更重要
工具走查之后,如果有条件,做一轮真实读屏用户测试。真实用户测试的重点不是让用户帮你找 bug,而是观察用户在使用时的心智模型和操作习惯。比如用户习惯用快捷键直接跳到表单第一个输入框,还是习惯逐字段 Tab 过去;用户对某个商品信息的理解是否和设计意图一致;用户面对“库存紧张”这类提示时的决策行为是怎样的,等等。
用户招募需要特别注意筛选标准。长期使用读屏软件的用户和偶尔打开无障碍模式体验一下的人,操作习惯和熟练程度差别非常大。如果混在一起测试,数据会有很大干扰。业内公认的思路是把用户分为几档:完全依赖读屏且超过五年经验的高频用户、有读屏使用基础但不算熟练的中度用户、以及从未用过读屏的新用户。三档用户测试同一份任务集,问题暴露的密度完全不同。对多数产品的无障碍成熟度而言,先保证高频熟练用户的体验不吃力,再去优化中等用户群体的学习成本,远比从零开始铺摊子更稳妥。
7.3 一套可复用的验收清单
以下是一份经历了多个项目打磨的验收清单,直接抄作业可用。每一步都对应前面章节提到的问题域,在执行时可以作为走查和用户测试的检查基准。
| 检查项 | 具体说明 | 验证方式 |
|---|---|---|
| 页面标题 | 每页有唯一且描述清晰的 title,切换页面时能播报 | 读屏实测 |
| 结构语义 | 导航、主体、侧栏、页脚等区域使用标准 landmark | 读屏 + DOM 检查 |
| 图片替代文本 | 商品图、图标、按钮图都有准确的可访问名称 | 自动化 + 人工走查 |
| 表单标签 | 所有输入框和显式 label 关联,必要时配 aria-describedby | 自动化 + 读屏 |
| 焦点顺序 | Tab 顺序符合视觉阅读逻辑,无焦点陷阱,有可见焦点样式 | 键盘走查 |
| 键盘操作 | 所有交互都可仅用键盘完成,无鼠标独占功能 | 键盘走查 |
| 动态内容播报 | 加入购物车、删除、优惠券生效、提交结果等有 live 播报 | 读屏实测 |
| 价格信息清晰 | 价格和原价、折扣信息以完整句子朗读,非碎片数字 | 读屏实测 |
| 规格选择反馈 | 每个选项有完整名称,选中状态清晰,缺货状态明确 | 读屏实测 |
| 表单错误反馈 | 错误提示与输入框关联,口语化描述,错误摘要可集中播报 | 读屏实测 |
| 验证码替代 | 有短信/语音/风险跳过等替代路径,错误提示明确 | 业务链路测试 |
| 支付结果确认 | 订单号、金额、售后入口信息完整,播报无遗漏 | 读屏实测 |
| 敏感信息安全 | live region 不含手机号、身份证号等敏感信息 | 代码检查 |
这份清单不需要一次性全部达标才上线,核心交易链路(搜索到支付)是最高优先级,先跑通再逐步覆盖长尾页面。从实践来看,把核心链路做到合格,涉及的成本可控,但收益(包括普通用户的体验提升)会非常明显。
8. 一些踩过的坑和最后的实话
写到这里,我想把过去几年在这个方向上踩过的坑和攒下的一点心得一并讲出来,希望后来的人少走几条弯路。
第一个坑是“无障碍等于给图片加 alt”。这是一种典型的外行认知,也是最容易让团队产生虚假安全感的理解。等真正用读屏软件跑一遍流程就会发现,无障碍的复杂度远超属性层面的修补。一个页面的语义结构、焦点逻辑、状态播报、Live Region 的交互节奏,每一项都需要单独设计。alt 只是万里长征第一步。
第二个坑是“做了无障碍但没做键盘操作”。很多开发以为读屏用户只靠手势或快捷键,不需要考虑 Tab 键顺序。实际上键盘操作是所有辅助技术的基础。鼠标用户不会被困在弹窗里,但键盘用户会;视觉用户能看到弹层背后的遮罩,但读屏用户不清楚焦点在哪里。键盘走查是成本最低、收益最明显的测试手段,强烈建议每个项目都从这一步开始。
第三个坑是“只测一次就宣判完成”。无障碍是一个与页面共存亡的持续指标。组件库升级、前端框架换代、运营位新模板上线,每次改动都可能破坏原有的无障碍能力。我遇到过不止一次,页面三个月前全部达标,三个月后因为改版把焦点顺序打乱,读屏用户卡在首页导航里出不来。所以从项目一开始就应该把无障碍检查接入发布流程,和 lint 一样自动跑。
第四个坑是“过度依赖 WAI-ARIA 属性”。ARIA 用对了是天才,用错了是灾难。一个平凡的 div 加了 role="button" 但不处理键盘事件,对读屏用户来说就是一个“能听不能按”的假按钮。ARIA 的正确用法是补充原生语义的不足,而不是替代原生控件的功能。能用原生 button 就用原生 button,能用原生 select 就用原生 select,这是我在项目中反复强调的第一准则。
基于我个人这些年的体会,无障碍改造最有意思的地方在于,它会反过来逼迫团队把产品逻辑梳理得更清楚。一个连焦点顺序都设计不清楚的页面,背后往往是信息架构的混乱;一个价格信息在无障碍环境下说不清楚的页面,视觉用户在快速扫货时其实也容易产生误解。所以别把无障碍当成“给盲人做的加分题”,它就是产品基础质量的一部分。
最后再分享一个小心得:如果你所在的项目组暂时抽不出精力做全链路改造,那就先把“搜索—筛选—商品详情—加购—结算—支付”这条主干跑通。主干通了,用户至少能完成购买这个核心任务。剩下的浏览推荐、评价晒单、退换货流程,可以放在第二个迭代再逐步完善。别贪多,先把一件事做到合格,再谈覆盖广度和深度。这条路没有捷径,只能一步一个脚印走。