优先使用原生HTML元素实现可访问性,如<select>、<nav><ul><li>和<button>,因其自带键盘导航、屏幕阅读器支持及语义结构,避免用<div>等元素模拟导致的ARIA状态不同步、交互缺失等问题。

原生 HTML 元素自带可访问性,不是“能用就行”,而是“不用额外补救就能被正确识别和操作”。关键在于选对标签、不破坏默认行为、不强行覆盖语义。
为什么优先用 <select> 而不是自定义下拉
因为 <select> 天生支持:Tab 进出、方向键切换选项、Enter 确认、屏幕阅读器自动播报“组合框,已选 X 项”、移动端唤起原生选择器。一旦用 <div> + JavaScript 模拟,你就得手动实现全部这些——漏掉 aria-expanded 同步、没处理 Escape 关闭、tabindex 错位,键盘用户立刻卡死。
- 适用场景:单选、无搜索、无图标、选项数 ≤ 15 条
- 禁用时直接加
disabled属性,无需额外 class 或 JS 控制 - 多选必须用
multiple属性,别试图用 checkbox 模拟 —— 那会丢失原生多选语义和快捷键(如 Shift+Click)
<nav> + <ul> 是导航菜单的唯一安全结构
只写 <nav><a>首页</a><a>关于</a></nav> 是无效的。屏幕阅读器会把它读成一串无结构的链接,无法告知“这是导航区域,共 2 项”。必须套 <ul> 和 <li>,否则语义断裂。
-
<nav aria-label="主导航"><ul><li><a href="/">首页</a></li></ul></nav>才是完整结构 - 多个
<nav>必须靠aria-label区分,不能都叫 “Navigation” - 当前页链接必须同时有
class="active"和aria-current="page",仅前者对读屏无效
自定义菜单触发器必须是 <button>,不是 <div> + role="button"
role="button" 只是“告诉”辅助技术“这像按钮”,但不会获得任何原生能力:空格/Enter 不触发、disabled 不生效、Tab 进不去、:focus-visible 不匹配、表单中不可见。硬补这些,等于重写 <button> 的全部逻辑。
立即学习“前端免费学习笔记(深入)”;
- 触发下拉的元素,一律用
<button type="button">,哪怕它看起来像文字链接 - 配合
aria-haspopup="listbox"和aria-expanded,状态由 JS 动态更新 - 禁用时用原生
disabled,不要只加 class 或移除 click handler
最常被忽略的点:所有 ARIA 属性必须随 JS 状态实时同步。比如菜单展开后忘了设 aria-expanded="true",或用户用键盘选中某项后没更新 aria-selected="true" —— 这些不是“锦上添花”,而是让读屏用户彻底失联的断点。



















