无障碍访问(Accessibility)

概述

为了更好地满足视障人士对于小程序的访问需求,小程序支持配置无障碍访问属性。
无障碍特性在读屏模式下可以访问,iOS可通过设置->通用->辅助功能->旁白打开,Android可通过设置->无障碍->TalkBack打开。
以 View 组件为例,开发者可以增加role和aria-label属性。 其中role表示组件的角色,当设置为'img'时,读屏模式下聚焦后系统会朗读出'图像'。设置为'button'时,聚焦后后系统朗读出'按钮'。 aria-label表示组件附带的额外信息,聚焦后系统会自动朗读出来。

无障碍样式

基础库会自动维护无障碍样式开关。当无障碍样式开启时,会在 HTML 根节点上添加 data-a11y="true";关闭时会移除该属性。开发者无需手动设置该属性,可以直接基于它编写选择器,在无障碍模式下提供更高对比度、更明显的焦点态或更大的点击区域。

[data-a11y='true'] .action-btn {
  min-height: 96rpx;
  outline: 4rpx solid #1677ff;
}

无障碍属性

以下 ARIA 属性可作为 props 直接传入任意组件,实现自定义无障碍语义。

属性说明
role语义角色,如 button、checkbox、slider、link 等
aria-label朗读文本,辅助技术读取此值描述元素
aria-labelledby引用其他元素的 id,辅助技术将该元素的文本作为当前元素的标签(适用于有独立标题的区域)
aria-describedby引用其他元素的 id,辅助技术将该元素的文本作为当前元素的描述信息
aria-disabled元素是否处于禁用状态
aria-hidden为 'true' 时辅助技术忽略该元素及其子树,适用于纯装饰性内容
aria-checked元素是否处于选中状态(适用于 checkbox、radio、switch)
aria-selected元素是否处于选中状态(适用于列表项、Tab 等可选中场景)
aria-expanded元素是否处于展开状态(适用于折叠面板等)
aria-haspopup元素是否具有弹出层(如下拉菜单)
aria-live实时区域更新策略,可选值:off(默认,不播报)、polite(内容更新完成后播报)、assertive(立即打断当前播报)
aria-atomic与 aria-live 配合,为 'true' 时辅助技术整体播报实时区域,为 'false' 时只播报变化部分
aria-relevant与 aria-live 配合,指定哪类变化触发播报,可选值:additions、removals、text、all
aria-required表单元素是否为必填项(适用于 input、textarea 等)
aria-flowto指定阅读顺序的下一个元素 id,覆盖默认文档顺序
aria-valuetext范围类元素当前值的人类可读文本(优先于 aria-valuenow 被朗读)
aria-valuemin范围类元素的最小值(适用于 slider)
aria-valuemax范围类元素的最大值(适用于 slider)
aria-valuenow范围类元素的当前值(适用于 slider)
tabindex元素在 Tab 键导航中的顺序;0 表示可聚焦,-1 表示不可聚焦

组件库内置 ARIA 属性

以下组件会内置对应的 ARIA 属性,开发者无需手动传入:

组件无障碍属性
Buttonrole="button" aria-disabled
Input / Textareaaria-disabled
Checkboxrole="checkbox" aria-checked aria-disabled
Radiorole="radio" aria-checked aria-disabled
Switchrole="switch" aria-checked aria-disabled
Sliderrole="slider" aria-valuemin aria-valuemax aria-valuenow aria-disabled
Pickeraria-haspopup="true" aria-disabled
Navigatorrole="link" tabindex="0"

示例代码

为 View 添加 role 和 aria-label

import React from 'react';
import { View, Text } from '@ray-js/ray';

export default function AccessibilityDemo() {
  return (
    <View
      role="button"
      aria-label="关闭对话框"
      tabindex="0"
      style={{ padding: '20rpx', background: '#f0f0f0', display: 'inline-block' }}
    >
      <Text>x</Text>
    </View>
  );
}

常见问题

为什么给 Button 传了 role 却没有效果?

Button 内部已内置 role="button",若传入自定义 role 会被内置值覆盖。如需自定义语义角色,请使用 View 等无内置 role 的元素。

aria-label 和组件内部文字哪个会被朗读?

当同时存在 aria-label 和组件内部文本时,辅助技术通常优先朗读 aria-label。建议当组件内部文字足以描述语义时,不额外设置 aria-label;对于纯图标按钮等缺乏文字说明的场景,务必设置 aria-label。

tabindex 的值如何选择?

通常只使用 0 和 -1:0 将元素加入默认 Tab 顺序,-1 使元素可通过脚本聚焦但不出现在 Tab 顺序中。不建议使用正整数,因为会破坏自然 Tab 顺序。