资讯动态

前端无障碍实战:为盲人用户重构在线购物体验

发布时间:2026/10/13 12:14:33 来源:尧图企业网站定制
第一次接触 DinamicX 这个项目时我心里其实打了个问号盲人也能在线购物这听起来像是一个“善意但很难落地”的想法。直到我把市面上的主流购物网站挨个用读屏软件过了一遍才发现问题远比想象中严重——商品图片没有替代文字、价格和销量挤在一行里读成一长串数字、加入购物车按钮的朗读名称含糊不清、结算页的优惠券入口既看不见也摸不着。说白了普通用户习以为常的“看到就点”购物流程对盲人用户几乎是处处碰壁。DinamicX 想解决的正是这个问题在不要求商家重做网站的前提下为视障用户搭出一条能走通的在线购物路径。这篇文章不聊虚的把我做这个项目的思路、踩过的坑、试出来的可行方案一次讲清楚。这篇文章适合谁看如果你是前端工程师、产品经理、独立开发者或者只是对无障碍Accessibility方向感兴趣都可以往下读。涉及的技术点不算深但每一块都有实际价值和可复现的细节拿过去就能参考落地。1. 盲人网购的真实困境问题远比想象中复杂1.1 从一次购物失败说起我在项目立项前做过一次“用户模拟测试”——关掉显示器只靠读屏软件去某购物平台买一支钢笔。流程是这样的打开搜索框输入“钢笔”回车然后开始听结果。第一层问题立刻暴露搜索结果页在屏幕上是以网格展示的每个商品卡片里有图片、标题、价格、销量、店铺名。读屏软件按顺序读下来会把这五个信息拆开播报但根本对不上号。用户听到的是图片图片图片图片——每张图片都在读它的替代文本而其中一半以上是空的或者干脆叫“商品图”接着是“29.00”“月销500”“某数码专营店”这一串信息。你想知道“29.00 是哪个商品的价钱”根本无从推断。就算用户运气好猜到了某个位置想点进详情页第二个问题又来了商品卡片本身没有正确的可访问名称。很多电商前端是a包裹整张卡片但内部又塞了数个span和img读屏软件往往把卡片当作“链接未命名”或者念出一段奇怪拼接的文字。等真正进了详情页更经典的坑出现了——商品描述里的关键信息全部写在图片里文字区域只有一句“主图有详情”。对普通用户来说滑动图片、放大看细节就完了盲人用户只能干瞪眼。这次模拟走下来我最大的感受是这已经不是“某个按钮没写 label”这类小问题而是整个页面信息架构对读屏用户不友好。把问题归因为“开发不重视”并不准确很多团队根本没意识到自己写在模板里的alt和aria-hidden会带来这么严重的后果。1.2 为什么主流购物网站这么难读主要有三个原因缺一不可其一电商页面的信息密度极高。一个搜索结果页相当于同时向用户展示几十张商品卡片每张卡片的视觉信息被读屏软件降维成一串串线性播报顺序又往往和视觉布局不一致。视觉用户可以“扫一眼”聚焦到感兴趣的商品读屏用户只能逐条听完信息获取效率差一个数量级。其二前端组件大量使用自研交互控件。今天随便打开一个购物网站都会看到懒加载图片、无限滚动、侧边栏抽屉、悬浮红包、限时秒杀浮层……这些组件在视觉上能吸引注意力但对读屏软件来说它们经常是“谜语”。无限滚动导致读屏用户永远摸不清列表有多长动态插入的浮层如果不带合适的 ARIA 状态属性焦点会莫名其妙跳走。其三也是最扎心的一点大部分电商迭代时只按“像素级还原设计稿”来验收没有任何无障碍验收环节。设计稿上有一个“加入购物车”的红色按钮开发写了个div classbtn视觉上完全一致但读屏用户听到的可能就是“按钮按钮”——因为没写rolebutton也没有可访问名称。这种问题只在读屏环境下暴露肉眼完全看不出来所以团队不自测的话基本永远发现不了。这三条原因叠加起来得出了一个结论盲人用户使用购物网站不是在“体验差”和“体验好”之间挣扎而是在“能用”和“不能用”之间走钢丝。1.3 盲人购物是“小众需求”还是“真实刚需”有人可能会说盲人用户数量占比不高商家不专门优化也情有可原。说实话我在项目早期也有这个想法但后来查了组数据就改变了态度——视障人群的规模远超大多数人直觉而且这个群体在日常生活中有强烈的独立购物需求。他们不想每次都麻烦家人朋友代买更不想被人牵着去线下超市听导购推荐一堆不合适的东西。最讽刺的是盲人用户恰好在很多方面都是“重度数字用户”手机上的读屏工具是他们获取信息、处理生活事务的主要通道。购物本来就是高频场景相比之下很多数字产品反而成了他们获取商品信息的“信息围城”。结论很简单这不是伪需求而是长期被技术忽略的刚需。DinamicX 的定位也因此清晰起来——不替代电商平台只在“商家页面”和“视障用户”之间做一个把信息理顺、把操作打通的无障碍翻译层。2. 整体设计思路不造轮子当翻译官2.1 方案选型为什么不做原生改造项目启动时团队内部先吵了一轮到底是在电商平台代码里加无障碍补丁还是做一层独立工具加补丁听起来最“正宗”直接给商品卡片补alt文案、给按钮加合适标签、优化焦点顺序一劳永逸。但实际操作起来难度和风险都很大。主流购物网站的页面结构高度复杂前端改造涉及商品录入系统、模板渲染、组件库、活动配置系统牵一发动全身。更现实的问题是我们开发组并没有权限去改第三方商家的代码。于是我们转向了第二条路做一个客户端层的“无障碍增强工具”通过对页面 DOM 结构和朗读顺序的实时干预把杂乱的信息重组为读屏友好的内容。这个思路听起来霸道但它的核心不是粗暴地改页面而是做三层处理感知——监听页面变化和用户操作理解——根据商品卡片、价格、按钮等 DOM 结构特征判断它是什么重构——在语音输出层面把信息整理成“商品名价格多少销量多少是否可加购物车”这种结构化句式。这个方案最大的好处是不依赖商家配合用户装上就能用而且即使页面布局千奇百怪只要 DOM 里还有信息理论上都能被重组。代价也很明显DOM 结构一旦改变识别逻辑就要跟着更新。这是项目里最耗费精力的一部分后面会单独讲。2.2 核心模块拆解DinamicX 从功能层面分成四个模块各管一摊第一读屏适配层。它对接的不是屏幕本身而是用户正在使用的读屏服务——不管用户用的是系统自带的读屏还是第三方辅助工具这套适配层都要保证输出的语义能被正确朗读。它负责把页面节点映射成可朗读的文本序列并管理朗读的优先级和打断规则。第二语义分析器。这个模块会扫描页面里的商品卡片、价格节点、评价节点、按钮控件通过 DOM 结构特征和文本模式来判断它们之间的归属关系。比如一个容器节点下面同时包含img、标题类class、价格类文本语义分析器会尝试把它识别为一个“商品卡片”然后把卡片内所有文本抽取出来按规则排序。第三操作映射器。当用户提出“加入购物车”或“立即购买”的指令时操作映射器要找到页面上对应的真实按钮并模拟点击。这需要做“语音指令到页面元素”的对应关系表容错率要很高。第四播报引擎。负责把重组好的信息用清晰、平缓的语速读出来并支持用户通过手势或按键快速切换阅读模式比如“只看价格”“只看优惠信息”“逐条浏览商品”。这四个模块加起来前端听上去像一个“无障碍中间件”技术上并不算惊世骇俗但胜在简单直接。2.3 为什么说“用 DOM 识别”是不得已的务实选择当初团队里也有人提议能不能直接对接电商平台的接口如果拿到了结构化 JSON 数据商品名称、价格、库存状态一清二楚根本不用去猜 DOM。这个提议听起来很美但同样走不通。个人开发者或小团队很难拿到主流电商的开放接口而且接口的电商数据往往是营销优先——给的是“活动标题”“推荐理由”不包含无障碍需要的“按钮描述是否清晰”“键位焦点是否可控”这类信息。所以我们落在了 DOM 识别这招上。它不优雅但它是唯一对第三方页面通用的方案。就像你要给一栋老楼装电梯最难的其实不是选电梯型号而是如何让楼里的住户都同意你施工。DOM 就是那栋老楼的管道线路你不能重排管道只能顺着既有管路想办法。3. 核心实现细节从语义标签到动态区域管理3.1 让商品卡片“开口说话”商品卡片识别是整个项目的第一道坎。我最初想到的办法是匹配固定的class名比如“goods-item”“product-card”但很快发现不同平台、不同模块甚至不同运营活动页的类名都不一样并且很多是编译后的乱码式类名。后来换了个思路不再猜类名而是分析结构特征。一个商品卡片的 DOM 结构通常具备三要素有图片节点、有文本节点、文本节点中通常包含价格特征比如“¥”符号或销量特征比如“月销”“评价”。我用一个启发式评分函数去判断命中越多特征分数越高高于阈值的节点就视为商品卡片。这个方案在常见电商页面上准确率还行但遇到奇葩布局还是会失效。识别出来之后第二步是整理卡片内的朗读顺序。卡片内的文本节点按视觉顺序排但读屏用户需要的是逻辑顺序我定的排序规则是商品标题 → 价格 → 销量 → 店铺/评价 → 操作按钮。这套规则的背后逻辑是用户在决定要不要买时最先关注的是“这是什么、多少钱、靠不靠谱”最后才轮到“怎么操作”。这里有一个技术细节值得单独说为了加快识别速度语义分析器在页面加载后用了一个requestIdleCallback在空闲时段做批量处理然后用MutationObserver监听动态变化的区域。比如用户翻到第二屏时新插入的商品卡片能被及时发现并编入朗读序列不会出现“列表已经滑过去了但用户还不知情”的脱节感。3.2 聚焦与轮播键盘操作和焦点管理的边界键盘和读屏用户浏览页面基本靠焦点在可交互元素之间移动。问题是购物网站里存在大量“视觉焦点不代表操作焦点”的情况。举个例子一个商品卡片整体可以点击进入详情但卡片内部还有收藏按钮、对比按钮标准键盘 Tab 会依次经过这些内部控件。结果就是用户按 Tab 键想跳过多个商品结果一个卡片就按了五六下。DinamicX 在焦点管理上做了很关键的改造把单个商品卡片内部的所有子按钮合并为一个“操作组”用户第一次 Tab 进入该卡片时读屏播报“商品某某价格多少进入详情”用户可以按特定键直接进入详情也可以让读屏展开卡片内部所有按钮的清单。这种设计把“浏览模式”和“操作模式”分开符合盲人用户的真实习惯——大多数时候他们是在扫街式地浏览不是每一步都想做决定。轮播图Carousel也是一大痛点。很多电商首页顶部有一个自动滚动的活动轮播视觉用户扫一眼就过去了但读屏用户会被反复打断。页面结构里轮播的内容确实是动态变化的读屏软件会不断播报新内容。我针对这种情况做了专门的区域隔离把轮播区域设为aria-hiddentrue并给轮播外面加了一个“跳过轮播”的提示链接用户可以选择跳到下一板块。这样做没有剥夺用户了解活动内容的机会只是把“被动轰炸”变为“按需读取”。3.3 表单校验的语音化提示把红色错误变成听得懂的提醒如果说商品卡片识别是“能不能买到”的问题那么表单校验就是“能不能买成”的问题。盲人用户最怕的流程就是结算页的收货地址表单。普通用户可以一眼看到“姓名张三电话138…”这样的文本框知道哪个是空的、哪里填错了。但读屏用户面对表单时最容易遇到两个问题第一页面没有用label for把提示文字和输入框关联起来读屏软件念不出“请输入手机号”这样的引导。第二输入错误时页面经常只在前端脚本里弹一个红色提示“请输入正确的手机号”但没有任何aria-describedby或rolealert机制把这个信息推送出来。用户为什么填错因为他根本不知道格式要求。DinamicX 在表单环节做的是“完整语音化”当用户进入一个输入框时播报这个框的名字和输入要求当用户输入过程中触发校验失败时自动插播一条清晰的语音提示并给出修正建议。技术上是通过监听表单的change事件和 DOM 内错误提示节点的内容变化来触发的。这里特别要提醒一个容易踩的坑很多校验错误提示是用纯 CSS 突出显示的比如把字体变红、加边框读屏软件根本感知不到所以开发自定义组件时要在错误消息节点上加rolealert或aria-livepolite这不是给盲人用户听的是给读屏软件听的。3.4 购物车与结算流程的“一站式播报”另一个细节是购物车页面的处理。购物车列表本身是一个表格结构但多数电商实现时用的是无序列表。靠读屏逐行听下来用户听到的是一串商品名、数量修改框、删除链接没有结构性概念。DinamicX 做了“购物车摘要”功能进页面时先播报“购物车里共有3件商品合计金额为……元最后一键结算按钮位于页面底部”这样用户就有一个全局认知然后再听每个商品明细。结算流程里更复杂的是优惠券。优惠券入口通常是个弹窗或浮层浮层打开后焦点不会自动移入读屏用户经常在“已打开优惠券面板”和“还在原页面”之间反复横跳。我们处理这种浮层的通用逻辑是检测到页面中出现新的dialog或aria-modal节点时自动把焦点移入该节点并追加播报“弹窗已打开”。浮层关闭时再恢复原焦点位置。这个逻辑如果做得好可以显著提升用户对“我在哪一层页面”的判断力。4. 从 0 搭建一套无障碍审计流程工具与测试方法4.1 基础工具链做无障碍项目最怕的就是“自己觉得做了无障碍一测全废”。所以我强烈建议从一开始就建立一套可重复执行的审计流程千万别等项目做完了再测。我们项目里用到的工具大致分三类自动化扫描工具这类工具能发现约 20% 的低级问题比如图片缺alt、按钮对比度不足、表单控件缺少 label。常用到的有开源的 axe-core能集成进浏览器插件或测试框架里。优点是快缺点是只能查出“自我可见的规则”查不出“语义顺序是否合理”“焦点路径是否顺畅”这类高层次问题。读屏软件这是最“硬核”的一环。桌面端有条件的话要同时测试多套读屏软件因为不同读屏软件对同一段代码的解析结果常常不一样。移动端至少也要拿系统自带读屏功能过一遍核心流程。颜色对比度检测工具很多无障碍问题集中在视觉层面比如浅灰色文字在白色背景上对比度不够。这类问题用眼看不准最好用工具直接测出对比度比值。4.2 三步走自动扫描 → 人工走查 → 真机测试我的习惯是先跑一组自动化扫描把能机器识别的问题全部揪出来修完后进入人工走查。人工走查时我会关闭显示器只用读屏软件和键盘操作按照真实用户的路径走一遍搜索商品 → 查看详情 → 加入购物车 → 提交订单。这期间发现的问题用表格记录下来标明页面位置、问题描述、触发的操作、期望行为、实际行为。其中有一个非常容易被忽视的地方人工走查时不能只测“正常流程”还要测“页面弹出了优惠券浮层”“有商品缺货”“网络请求失败”这些异常状态。盲人用户在异常状态下的困惑程度远高于视觉用户因为异常提示往往不播报。真机测试则要在不同的操作系统和读屏软件上进行不能只看模拟器。模拟器的读屏表现和真机差异很大尤其是焦点管理这一块。我们当时就被坑过一次在桌面浏览器上一切正常一上手机读屏状态栏里的商品数量提示怎么也读不出来排查了好几天发现是移动端读屏对子窗口切换的支持跟桌面版不同。4.3 一份可复用的审计检查清单按照上面三步走的流程我整理了一个检查清单项目组里后续做无障碍优化时基本照着它过检查项操作方式通过标准商品卡片朗读顺序读屏按序浏览先听商品名再听价格再听销量/评价图像替代文本逐张听完所有图片没有“图片”“未命名”这类无意义描述卡片内部按钮键盘 Tab 依次通过能合并时合并不能合并时名称清晰可辨轮播区域启动页面后等待3秒不被自动播报打断可通过“跳过”跳出表单标签关联读屏进入输入框能听到输入框名称和格式提示校验错误反馈故意输错后提交错误提示语音可感知且给出修正建议弹窗焦点管理触发优惠券/客服弹窗焦点自动移入弹窗关闭后回到原焦点购物车摘要进入购物车页面首先播报总件数和总金额结算路径从购物车走到提交订单全程无需视觉辅助即可完成键盘可操作性只靠键盘完成一次购物无任何鼠标点击依赖这份清单现在看很朴素但每一条都是踩过坑之后沉淀下来的直接复制去用没有问题。5. 常见问题与踩坑实录5.1 动态加载的商品列表读屏不播报项目第一个版本上线后收到的最多反馈就是“商品列表滚到底部时新加载出来的商品读屏不播报”。原因很典型无限滚动动态插入的新节点没有触发读屏的感知机制。读屏软件一般会关注页面顶部的aria-livepolite区域如果新增内容不在这个区域内它就“看不见”。我当时的解决办法是在商品列表容器外层加一个隐藏的aria-livepolite区域检测到列表数量增加时往这个区域写入一句“已加载更多商品当前共30件”。这一招简单有效但要注意不能写得太频繁否则用户会被连续播报吵到。我的经验是每次滚动加载最多播报一句并且要把新增区域的内容摘要出来而不是只说“内容更新了”。5.2 自定义组件的“可访问性陷阱”购物网站里有很多自研组件最常见的是“商品数量选择器”和“规格选择器”。视觉上它们是一个加减按钮加一个数字框但在 DOM 里很可能是一个div包着两个span根本没有键盘焦点。读屏用户就算听懂了也无法改变数量。这种问题在自动扫描工具里通常发现不了因为工具只查“是否存在可见控件”查不出“控件是否可操作”。我们的处理方案是写了一套“组件补全器”对常见控件模式加减按钮、下拉选择、单选卡片等建立识别样板一旦识别出对应组件就动态给它补上rolespinbutton、aria-valuenow、aria-valuemin、aria-valuemax等属性并注册键盘加减事件。说白了就是帮页面把“没写完的无障碍代码”补写完。这套逻辑很有价值但维护量确实不小因为电商的组件形态更新太快每隔几个月就要新增几种样板。5.3 读屏软件之间的行为差异做无障碍开发一定要记住一条铁律读屏软件不是铁板一块它们之间的行为差异比浏览器之间还大。同一个aria-live区域在桌面端读屏里会老老实实播报在移动端读屏里可能直接被忽略。同一个dialog某些读屏版本会优先朗读标题某些版本会直接朗读全部内容。所以我在项目里养成了一个习惯所有关键交互都不只依赖一种 ARIA 属性而是“ARIA 属性 结构化 HTML 语义”双保险。比如一个商品卡片可以被识别成一个可点击区域我在自定义增强里给它加上rolelink再确保内部有alt描述的图片、加上清晰的标题文本。这样即使某个读屏不理会role它至少能读到里面的文字内容不会完全失效。5.4 常见问题速查表问题现象可能原因排查思路读屏不播报新加载的商品新节点未在aria-live区域内给列表容器外层加隐藏的 live 区域读屏播出一串“图片图片图片”图片缺少有效alt逐张检查图片补充描述性替代文本用户无法修改商品数量加减按钮不支持键盘焦点给控件补role和键盘事件焦点卡在弹窗里出不来弹窗缺少焦点闭环管理打开时移入焦点关闭时归还焦点校验报错播报不出来错误提示无aria-live或 alert 角色在错误消息节点上加rolealert某读屏播报正常但另一款不读ARIA 兼容性差异用语义化 HTML 标签兜底不依赖单一 ARIA 属性轮播反复打断朗读轮播内容动态变化未隔离设为aria-hidden提供手动查看入口这张表是我在日常维护中积累的每次排查新问题时我都会先对照一遍省去不少试错时间。6. 无障碍改造的收益与成本性价比怎么看6.1 技术投入没有想象中高很多人潜意识里觉得“无障碍优化”是一个大工程要做专门的系统、配专门的人力。但从 DinamicX 的实际经验看针对购物场景做无障碍化技术投入主要集中在三块DOM 特征识别规则的编写、语音播报的编排、各类控件的焦点管理。这三块都有成熟的前端基础可以借鉴不需要发明任何新算法也没有复杂的机器学习任务。更准确地说它更像“前端结构化 规则引擎 交互设计”的结合体一个中高级前端工程师带着一个懂用户需求的测试同学基本可以搭起一个可用版本。真正的高成本不在写代码而在“持续维护”。电商页面每周都有活动页上线新页面新结构层出不穷识别规则会持续失效。所以如果要做类似产品建议从一开始就设计成“规则可配置化”把识别逻辑做成线上可更新的配置而不是写死在前端代码里。这是一个很多人忽略但极其重要的架构决策。6.2 对普通用户也有反向体验提升做无障碍改造的过程中我反复感受到一件事无障碍优化的很多手段对普通用户同样有正向价值。语义化标签让页面结构更清晰网页代码可读性更强稳定的焦点管理让键盘用户也能顺畅操作清晰的信息层级减少视觉噪音普通用户在快速浏览时也更容易抓到重点。购物场景里没有哪个用户喜欢页面弹一堆轮播广告也没人喜欢商品信息挤成一团。很多无障碍优化本质上是“信息设计优化”受益的不只是特定人群。我在给一个模拟项目X做改造时发现商品卡片的朗读顺序优化了之后普通用户浏览时的点击率也有提升因为他们找到关键信息的速度变快了。这个结果不算意外但它给了我们一个思路无障碍不应该被当作“附加义务”它可以是产品体验升级的抓手之一。6.3 从产品价值到社会价值购物是每个人日常生活的一部分对盲人用户来说能够在网上独立完成一次购物不只是“找到了一件商品”更意味着一种独立生活的可能。不需要在每一个生活决策上都依赖他人能够自己比较价格、看评论、选规格、下单这种掌控感在普适体验里稀松平常在某些群体的世界里却格外珍贵。这也是我做这个项目后最强烈的感受技术能做的事情往往比我们想象的多。很多时候不是技术做不到而是我们根本没意识到“有人需要它”。DinamicX 这样一个工具本质上不是炫技而是在为一种需求找到一个务实的出口。它不需要替代电商平台也不需要颠覆交互范式它只是让现有的购物链路多了一个对盲人用户友善的入口。做完这个项目再回看最大的体会是无障碍不是某个阶段的“补丁”而是贯穿设计、开发、测试全流程的思维方式。哪怕是给一个按钮写aria-label这种小事背后都意味着有人将因此少碰一次壁。如果你也有一个正在做或想做的产品我真心建议你在开发早期就带上无障碍的视角不用十全十美哪怕先覆盖最核心的一条操作路径价值都会远超你的预期。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑