打开网易新闻 查看精彩图片

全球15%的人口存在某种形式的残障,但你的React应用可能从未为他们设计过。这不是道德审判,是产品漏洞。

语义化HTML不是"锦上添花",是React组件的地基。当你用div堆砌导航栏时,屏幕阅读器用户听到的只是一串无意义的"div, div, div"。

本文用一组真实代码对比,展示如何把"能跑"的组件改成"谁都能用"的组件。没有框架迁移,没有重构噩梦,只有标签的精准替换。

01|导航栏的"身份危机":div vs nav

01|导航栏的"身份危机":div vs nav

这是某电商后台的真实代码片段。开发者用div实现了完整的顶部导航,视觉上毫无问题,直到测试团队打开屏幕阅读器

「我听到的是'div,链接,div,按钮,div',完全不知道这是导航区域。」一位视障测试员在反馈中写道。

问题出在语义缺失。div对辅助技术而言是透明容器,而nav标签会明确告知"这是一个导航地标"。

改造只需一步:把外层div换成nav,内部链接保持原样。屏幕阅读器用户现在能听到"导航,链接列表,首页",并可通过快捷键直接跳转到该区域。

ARIA角色(Accessible Rich Internet Applications,无障碍富互联网应用角色)是补救方案,但原生语义标签永远是第一选择。nav、main、aside、footer这些HTML5元素,在React中直接可用,零学习成本。

02|按钮的"伪装游戏":为什么onClick不能滥用

02|按钮的"伪装游戏":为什么onClick不能滥用

React开发者喜欢用div+onClick模拟按钮。样式自由,行为可控,看起来是双赢。

直到你尝试用Tab键聚焦它——失败。用Enter键激活——失败。屏幕阅读器播报——"文本,可点击",而非"按钮"。

键盘导航是无障碍的底线。原生button标签自带焦点管理、键盘事件、角色声明,div需要手动补齐全部功能:

tabIndex="0"让元素可聚焦,onKeyDown捕获Enter/Space,role="button"声明身份,aria-pressed处理状态。四行代码,四个可能遗忘的漏洞。

更隐蔽的问题是事件委托。div模拟的按钮在事件冒泡、表单提交、禁用状态等场景下行为不一致,调试成本远超样式覆盖的工作量。

一个原则:能点的东西,先看是不是button;不是button,再写aria。

03|响应式断点:从"设备优先"到"内容优先"

03|响应式断点:从"设备优先"到"内容优先"

传统响应式设计以设备为锚点:iPhone 375px,iPad 768px,桌面1024px。这种思路在React组件库时代已经过时。

内容决定断点。侧边栏在320px时折叠,不是因为"手机",而是因为"内容挤爆了"。

CSS容器查询(Container Queries)让组件自主响应父容器宽度,而非视口宽度。一个卡片组件在侧边栏内是垂直布局,在主内容区是水平布局,无需props传递设备类型。

React中配合useRef和ResizeObserver(尺寸变化观察者)可实现容器查询的polyfill。代码量不大,但彻底解耦了组件与设备假设。

图片响应式常被忽视。srcset属性让浏览器根据DPR(Device Pixel Ratio,设备像素比)和视口自动选择分辨率,避免移动端加载4K图浪费流量,或桌面端模糊失真。

04|表单的无障碍陷阱:label不是装饰品

04|表单的无障碍陷阱:label不是装饰品

placeholder替代label是高频错误。灰色提示文字在输入后消失,认知负荷用户、记忆障碍用户、屏幕阅读器用户同时陷入困境。

正确做法:label始终可见,通过htmlFor与input的id绑定。视觉上需要极简风格?用sr-only类隐藏,但保留DOM关联。

错误提示需要三重反馈:边框色变(视觉)、图标变化(认知)、aria-live区域播报(听觉)。React中可用useId生成唯一标识,避免服务端渲染的id冲突。

焦点管理是表单的最后防线。提交后错误字段自动聚焦,模态框关闭后焦点返回触发按钮,这些细节决定产品是否"能用"与"好用"。

05|测试:自动化工具能抓多少漏洞

05|测试:自动化工具能抓多少漏洞

axe-core可以集成到Jest测试流,在CI阶段拦截对比度不足、缺失label、错误ARIA等基础问题。但它测不出"这个流程对自闭症用户是否友好"。

真实用户测试不可替代。招募残障用户参与可用性测试,成本远低于诉讼赔偿或品牌损失。微软、苹果的无障碍团队规模,本质是风险管理的数字换算。

浏览器开发者工具的Lighthouse(性能与质量检测工具)评分是起点,不是终点。90分以上的网站仍可能有致命的键盘陷阱。