可访问性设计系统必须从html语义出发,将结构、交互约束内嵌组件定义中;优先使用原生语义标签(如),严格规范aria-current取值与焦点管理,通过组件库硬约束保障一致性。

可访问性设计系统不是“加一层ARIA”就能成立的,它必须从HTML规范本身出发,把语义、结构、交互约束 baked in 到组件定义里——否则每次手写都可能漏掉 aria-current、tabindex 或 aria-labelledby,导致键盘用户卡死或读屏器静默跳过。
用原生语义标签替代 role="xxx" 的第一道防线
很多团队一上来就给 <div> 打上 <code>role="button" 或 role="tab",这是高风险起点。浏览器对 <button></button>、<nav></nav>、<ol></ol> 等原生元素有内置的可访问性契约:自动获得焦点、默认键盘行为(Enter/Space 触发)、隐式 role 和状态同步能力。
- 所有按钮必须用
<button></button>,禁用时用disabled属性(而非仅 CSS 灰显) - 步骤向导优先用
<ol><li></ol>,而非<div class="step"> —— 语义已传达“有序序列” <li>标签页的标题容器必须是 <code><ul role="tablist"></ul>,但每个 tab 必须是<button role="tab"></button>,不能是<span></span>+ JS 模拟 - 表单控件必须配
<label for="id"></label>或嵌套写法,for和id值必须严格一致 - 在步骤向导中,当前步骤的
<li>应设aria-current="step",且该<li>内必须包含可聚焦元素(如标题或第一个输入框),否则键盘焦点无处落脚 - 在面包屑导航中,当前页链接必须设
aria-current="page",且只能加在<a></a>上,不能加在<li>容器上 - 导航栏中的“首页”链接若为当前页,也应设
aria-current="page",而非依赖视觉样式判断 - 切勿在非导航/非步骤场景滥用该属性,例如轮播图当前项用
aria-current="true"是无效且混乱的 - 标签页切换后,焦点应移到新激活的
<button role="tab"></button>上,并确保其aria-selected="true"已同步更新 - 步骤向导进入新步骤时,焦点应落在该步骤的
<h2></h2>或第一个<input>上,而非留在旧步骤的“下一步”按钮 - 模态框打开后,焦点必须 trap 在内部,且初始焦点应设在第一个可交互元素(如关闭按钮或主操作按钮)
- 避免使用
tabindex="-1"后再.focus()的“半吊子”方案——必须同时保证该元素在 Tab 顺序中可达(即不被跳过),且视觉焦点可见(不设outline: none) -
alt=""仅用于纯装饰性图片(如分隔线、背景花纹),告诉辅助技术完全跳过;含信息的图标(如搜索放大镜)必须写描述性alt,如alt="搜索" -
aria-label适用于无可见文本的控件,如仅用 SVG 图标的按钮:<button aria-label="关闭"><svg>...</svg></button> -
aria-labelledby适用于复用页面中已有文本的情况,比如一个图表下方有标题<h3 id="chart-title">2025 年用户增长趋势</h3>,则图表可写<img aria-labelledby="chart-title"> - 禁止同时使用
aria-label和aria-labelledby,后者优先级更高,前者会被忽略
aria-current="step" 和 aria-current="page" 的使用边界
aria-current 不是万能高亮开关,它的值必须精确匹配上下文语义,否则会误导屏幕阅读器。错误示例:aria-current="true" 或 aria-current="active" —— 这些值无效,会被忽略。
焦点管理不是“加个 focus() 就完事”
动态切换内容(如标签页切换、步骤跳转)后,焦点必须明确落到新区域的逻辑起点,否则键盘用户会迷失在空白或不可见元素上。这需要结合 DOM 结构和 ARIA 状态共同控制。
alt=""、aria-label、aria-labelledby 的选择逻辑
三者解决不同问题,混用或互换会导致冗余播报或信息缺失。核心判断依据是:这个元素是否承载独立语义?是否已有可见文本?是否需复用其他元素文本?
真正难的不是记住这些规则,而是让它们成为组件库的硬约束:比如 Button 组件的 props 必须校验 asChild 是否合法,TabList 组件必须强制要求每个 tab 提供 id 并自动绑定 aria-controls。否则,可访问性永远停留在“人肉检查清单”阶段,而不是设计系统的内生能力。











