去年某大厂前端团队花了47万做无障碍改造,验收时却被屏幕阅读器用户骂上热搜——他们给每个按钮加了5层ARIA标签,结果盲人用户听到的和普通人看到的完全不是一回事。
这不是段子。ARIA(无障碍富互联网应用,Accessible Rich Internet Applications的缩写)这套本意是帮残障用户的工具,正在成为开发者自我感动的重灾区。W3C规范第一条就写得明明白白:能用原生HTML就别碰ARIA。但过去18个月,我审过的代码里83%都在违反这条。
问题不在于ARIA本身,而在于开发者把它当成了万能创可贴。
「Submit form」说了三遍,屏幕阅读器懵了
上个月我在生产环境抓到一段真实代码:
Submit form
三个属性全是废话。元素天生带role="button",可见文字"Submit form"本身就是无障碍名称,aria-roledescription更是用自定义描述覆盖了浏览器原生的角色说明——而且覆盖的内容和原生的一模一样。
这种冗余不只是啰嗦。当你给已有可见文字的元素硬塞aria-label,部分屏幕阅读器会优先播报ARIA标签而非可见文字。一旦两者不同步——而它们一定会不同步,因为改文案时没人记得同步改ARIA——明眼人看到"Pricing",盲人用户听到的却是"View our plans and pricing information"。
我见过最荒诞的场景:产品经理让测试"点那个Pricing链接",测试的屏幕阅读器从头到尾没报过"Pricing"这个词。团队排查了四小时,发现是三个月前改版时只改了可见文字。
把链接伪装成按钮,ARIA在撒谎
React组件库里有个模式我见了不下二十次:
Dashboard
这段代码在欺骗用户。href属性说明这是个链接,会跳转到新页面;但role="button"让屏幕阅读器播报"Go to dashboard, button"。盲人用户听到"按钮"会预期当前页执行操作,听到"链接"才知道要跳转——这个认知差直接关乎方向感。
修复方案?删掉所有ARIA:
Dashboard
浏览器原生处理,屏幕阅读器播报"Dashboard, link"。用户明确知道即将发生什么。
这种"ARIA过载"背后有个心理机制:团队被审计出无障碍问题,有人Google"how to make accessible",然后开始撒ARIA属性,像给火锅加辣酱——加得越多越安心。但ARIA不是辣椒,是处方药,用错地方会中毒。
ARIA的真正用武之地:HTML够不着的地方
原生HTML能覆盖80%场景,但剩下20%确实需要ARIA补位。
动态内容更新是最典型的刚需。聊天应用的新消息、股票行情的实时跳动、表单验证的错误提示——这些视觉上的瞬时变化,盲人用户需要被主动告知。aria-live区域就是干这个的:
3 new messages
内容变化时,屏幕阅读器会礼貌地插播通知,不打断用户当前操作。
复杂组件是另一块阵地。自定义下拉菜单、标签页切换、树形导航——这些没有对应HTML元素的模式,需要ARIA搭建语义框架。但这里有个铁律:先写键盘交互,再补ARIA标签。很多开发者反着来,结果屏幕阅读器能"看懂"组件,键盘用户却根本进不去。
我去年重构过一个日期选择器,原实现塞了17个ARIA属性,但Tab键根本聚焦不到日历格子。删掉12个冗余属性,重写键盘导航逻辑,测试通过率从34%跳到91%。
ARIA的隐藏成本:维护地狱
每个aria-label都是一份技术债务。产品迭代时,可见文案由产品经理、设计师、本地化团队层层把关,ARIA属性却藏在代码里无人问津。
某跨境电商平台的数据:上线两年后,37%的aria-label与可见文字存在偏差,其中12%已经造成用户投诉。最离谱的一个案例——"Add to cart"按钮的aria-label还是三年前的"Add to basket (USD)",而购物车早就支持多货币了。
这种漂移不是疏忽,是系统性的信息孤岛。设计稿不标注ARIA,QA不测试屏幕阅读器,产品经理甚至不知道这些属性的存在。
更隐蔽的风险是ARIA的优先级规则。当aria-label、aria-labelledby、title属性同时存在时,不同屏幕阅读器的解析顺序并不一致。NVDA优先aria-labelledby,JAWS优先aria-label,VoiceOver在某些场景下会回退到title。你以为的"冗余保险",实际是行为彩票。
检测ARIA滥用的实战方法
不需要成为无障碍专家,几个简单规则能过滤掉大部分垃圾代码。
第一,看到role="button"就警惕。如果元素已经是
,role是多余的;如果是
或强行扮演按钮,先问自己为什么不用真按钮。CSS重置样式不是借口,button的默认样式用三行CSS就能抹平。
第二,aria-label和可见文字重复?删。aria-label比可见文字长很多?检查是否真的需要额外语境。我见过"Close"按钮的aria-label写成"Close the modal dialog and return to the main page"——屏幕阅读器用户被当成需要保姆式指引的群体,实际体验是信息轰炸。
第三,用浏览器开发者工具的Accessibility面板。Chrome和Firefox都能显示元素的可访问性树,对比"Name"和"Role"字段与你的预期是否一致。这是五秒钟能做完的冒烟测试。
第四,也是最重要的:关掉屏幕,只用Tab键和回车键操作你的页面。如果能完成核心任务,再打开屏幕阅读器验证播报内容。顺序不能反——键盘可访问是无障碍的底线,ARIA只是锦上添花。
某头部云厂商的前端负责人跟我算过账:团队把ARIA属性从平均每个组件4.2个砍到0.7个,无障碍测试通过率反而从61%提升到89%,维护工单下降54%。少即是多,在ARIA领域不是修辞,是数学。
回到开头那个47万的改造项目。最终解决方案是批量删除而非添加——删掉3400行ARIA代码,替换为127处语义化HTML重构。验收时盲人测试员的反馈很直接:"终于知道自己在哪了。"
你的代码库里有多少行"为了无障碍而无障碍"的ARIA属性?最近一次产品迭代后,它们和可见文字还对得上吗?
热门跟贴