17370845950

如何让自定义下拉菜单(非 select)被屏幕阅读器正确读出?
关键在于用正确ARIA属性模拟原生select语义:触发按钮设role="combobox"和aria-haspopup="listbox";下拉容器设role="listbox"及aria-labelledby;选项用role="option"并动态管理aria-selected;配合aria-label/aria-valuetext提供清晰标签与实时反馈。

关键在于用正确的 ARIA 属性模拟原生 select 的语义和行为,让屏幕阅读器识别出“这是一个可展开的控件,当前有选中项,列表是它的选项集合”。

用 role="combobox" 和 aria-haspopup="listbox" 标明控件类型

自定义下拉的触发按钮(比如那个带箭头的输入框或按钮)必须声明语义:

  • role="combobox" 表示这是一个组合输入+下拉选择的控件(比 buttondiv 更准确)
  • aria-haspopup="listbox" 明确告诉屏幕阅读器:点击/空格/回车后会弹出一个列表型菜单(不是菜单栏 menu 或对话框 dialog)
  • 如果支持键盘输入搜索(如带过滤的下拉),还要加 aria-expandedaria-controls(指向列表容器 ID)

为下拉列表容器设置 role="listbox" 和 aria-labelledby

展开后的选项容器不能只是 div 包着一堆 div,要赋予明确角色:

  • 外层容器设 role="listbox",这是 ARIA 中表示可选列表的标准角色
  • 加上 aria-labelledby,值为触发按钮的 ID,建立视

    觉控件与列表的语义关联(屏幕阅读器读列表时会带上按钮的标签名)
  • 避免用 role="menu" —— 它适用于右键菜单、应用菜单栏,不适用于表单选择场景

每个选项用 role="option",并管理选中状态

列表里的每一项必须是独立的可选单元:

  • 每项设 role="option",而非 buttondiv
  • 当前选中项加 aria-selected="true",其余为 "false"(注意:不是用 CSS class 模拟,必须是真实属性)
  • 确保选项可通过键盘导航(/),焦点能落在每个 role="option" 上,并触发 aria-selected 切换
  • 若支持多选,还需加 aria-multiselectable="true" 并配合 aria-selected

提供可访问的标签和实时反馈

屏幕阅读器需要知道“这是什么”以及“现在选了什么”:

  • 触发按钮本身要有清晰的可访问名称:可用 aria-label(如 aria-label="请选择城市"),或用 aria-labelledby 关联外部 label 元素
  • 当用户用键盘或鼠标选中某一项后,及时更新触发按钮的文本内容,并同步更新 aria-valuetext(例如 aria-valuetext="已选择:北京市"),让屏幕阅读器在焦点离开前读出最新值
  • 避免仅靠颜色或图标传达状态(如仅用勾选图标表示选中),必须有文字或 ARIA 层面的明确表达

不复杂但容易忽略:所有 ARIA 属性都要随交互动态更新,静态写死会导致语义失效。测试时用 NVDA + Firefox 或 VoiceOver + Safari,亲自用键盘操作一遍,听它怎么读。