- 快速开始
- JSX 介绍
- JSX+ 介绍
- 组件
- 事件处理
- 样式设置
- Hooks 介绍
- Driver 介绍
- 容器差异
- 工程介绍
- 目录结构
- 应用配置
- 应用入口
- 生命周期
- 路由管理
- 简介
- 语法约束
- Hooks
- 多端组件开发
- API 使用
- 静态资源引用
- 项目构建配置
- 页面配置
- 使用原生项目配置文件
- Rax 与小程序代码混用
- FAQ
- 更新日志
- 简介
- 环境变量与 Framework
- Weex Style 支持表
- Weex 组件
- Weex 模块
- 页面降级
- JS Service
- Bundle 解析
- 事件与手势
- 事件通信
- Weex 国际化
- Weex 常见问题
- 简介
- Document
- App Shell
- 代码分离
- 保存至桌面
- 渲染节点快照
- 预加载和预渲染
- 页面保活
- 缓存控制
- PHA 介绍
- 快速开始
- 编码指南
- 数据请求
- FaaS 接入: Now
- FaaS 接入: FC
- 与 Node 应用集成
- 数据请求
- 异步编程
- Rax 错误码
- 简介
- Lite 工程
- 云端一体化工程
- 插件配置
- 插件开发
- 插件简介
- build-plugin-rax-app
- build-plugin-rax-component
- build-plugin-rax-multi-pages
- build-plugin-rax-ssr
- build-plugin-rax-compat-react
- rax-plugin-app 0.1.0 升级
- 调试 Web
- 调试小程序
- 加载性能优化
- 渲染性能优化
- 从 Rax 0.x 升级
- 从 React 迁移
- API 概述
- render
- hydrate
- createPortal
- findDOMNode
- setNativeProps
- getElementById
- unmountComponentAtNode
- createElement
- cloneElement
- createFactory
- isValidElement
- Children
- memo
- Fragment
- createRef
- forwardRef
- useState
- useEffect
- useLayoutEffect
- useContext
- useRef
- useCallback
- useMemo
- useReducer
- useImperativeHandle
- PropTypes
- version
- ActionSheet
- Background
- Keyboard
- Animation
- Transition
- Toast
- Alert
- Confirm
- Loading
- Navigate
- ChooseImage
- Image
- Request
- Network
- File
- Env
- Device
- Clipboard
- AppState
- AsyncStorage
- Accelerometer
- 组件概述
- Text
- View
- TextInput
- Link
- Icon
- Image
- Picture
- Video
- ScrollView
- RecyclerView
- Waterfall
- Embed
- Countdown
- Canvas
- RefreshControl
- Slider
- Modal
- Weex JS Service
- Rax 长列表最佳实践
- 如何减小 Bundle Size
- Rax 0.x 开发工具
- Native 知识扫盲
- iOS 无障碍
- Rax 性能最佳实践
- 从零上手 Rax
- Rax v0.6 组件体验升级
- Rax v0.5 建立服务体系
- Rax v0.3 跨端生态建设
- Rax v0.2 基础能力建设
- 2016 淘宝双促中的 Rax
- Why Rax?
iOS 无障碍
引子
这篇教程旨在帮助开发者快速上手 Rax iOS 上的无障碍开发。
无障碍,即「accessibility」(常常缩写成「a11y」),是相对有障碍访问而言的,常见的有障碍访问场景有两类。
一种是用户因为生理缺陷,没有能力按正常的交互方式访问,举几个例子:
- 视障人士看不见或看不清,无法感受手淘上的信息,动效,氛围;
- 听障人士听不见或听不清,无法听到音乐以及视频的语音部分;
- 老年人视力和听力的退化。
一种是用户因为客观原因短时间内无法按正常的交互方式访问,比如开车的时候不方便看着屏幕操作。
无障碍的基本目标是使用户接收到产品想要传达的信息,更高的目标则是所有用户接收到的信息是同等的。
据统计,目前每天至少有 4 万以上的用户在访问手淘 iOS 版本(双十一当天达到了 14 万),Android 手淘用户则更多。而由于链路上的无障碍问题,双促实际进入会场(手淘 iOS)浏览的用户在双十二当天也只达到了一千多。这些数字多少说明了无障碍的必要性,探索空间和挑战。
iOS 上的解决方案和 VoiceOver
iOS 本身提供了一系列的 解决方案 。
比如用户能够借助 Siri(语音助手),通过语音来控制 IOS 完成一些简单的操作以及得到一些反馈,弱视用户可以通过设置对比度,字号来辅助阅读。
大部分功能都可以在「设置」- 「辅助功能」设置。
其中,比较强大的是 VoiceOver 功能(在 iOS 11.2 以上版本中,VoiceOver 有了中文名「旁白」)。
VoiceOver 开启后,操作方式就和原来不一样了,需要通过特定的手势操作。
通过单指单击来访问界面元素,如果元素可访问,元素会获得焦点,元素周围出现黑框,如果正常配置,VoiceOver 会依次读出元素的标签文本,角色(role),提示(hint)。其中,标签文本之后会有一个短暂的停顿,提示之前则会有一个较长的停顿。这是无障碍中最基础也是最需要保证的流程。
当元素是链接或按钮等可交互的角色时,单指双击会触发行为,等同于正常模式下的点击操作。
除了直接点屏幕来访问元素之外,可以通过单指左滑和右滑按顺序遍历元素,通过三指上滑和下滑在列表元素上跨页浏览。
VoiceOver 还提供了转子功能,用户可以拨转子在多个配置中选择,然后通过单指上滑和下滑来调节这个配置。
更多手势参见 这个手册 。
我们要做的是在 VoiceOver 开启状态下,保证用户操作畅通,提升体验。
常规操作
合理划分焦点
Weex 中的容器类型组件默认无法获取焦点,例如:
- div
- a
- cell
添加 accessible={true}
属性可以使这些组件能够获得焦点,同时子组件也都将无法获得焦点。
对默认可以获得焦点的组件而言,例如
- text
- image
- input
- switch
添加 aria-hidden={true}
属性来使这些组件无法获得焦点。
对一般的文本内容,例如活动规则说明,用户协议等,我们不需要做额外处理。
对于图片,如果是无意义的氛围图,一般有两种处理方式,添加 accessible={true}
使其对用户不可见,或为了防止大面积的区域无焦点,使图片的容器可以获得焦点。
对点击产生跳转或交互行为的区域,一般遵循 焦点区域最大化 , 个数最小化 原则。举几个划分的例子:
- 一个焦点
- 焦点重叠
- 多个焦点
检查焦点遍历是否正常。
一行多列布局焦点乱序问题
非通栏的布局下,焦点的遍历顺序和焦点的 top 有关。例如下图这个布局,实际编辑顺序为 A1,B1,A2,A3,B2,B3
而下图这个布局,实际编辑顺序为 A1,B1,A3,B3,A2,B2
目前尝试的解决方案是给容器添加属性 groupAccessibilityChildren={true}
,使得系统优先按组进行遍历。为了保证上述例子中的顺序为 A1,A2,A3,B1,B2,B3,需要给三个 A 结点的容器,A2,B2 的容器分别设置属性。但在 list 中是无效的。
元素内容语义化
默认除了 text 组件获得焦点后会读出包裹的文本内容外,大部分组件获得焦点后是无法读出内容的。
目前比较严重的问题是页面上大部分的图片,获得焦点后,仅读出「图片」。
添加 aria-label="语义化内容"
可以自定义内容。先看一个例子。
- 焦点 1 的内容模板为:
${标题} ${利益点} ${宣言}
,多个信息之间用 空格 分隔 - 焦点 2 的内容为 直播中 即可
内容编写的原则:
- 尽可能和包裹的信息对等
- 多条信息之间用空格号分隔
- 不用刻意添加补充文案
时刻
24 小时制 的时刻系统会按字符一个个读出,需要转化成 12 小时制 的写法,比如 23:58
要写成 11.58AM
。
隐藏价格
大促预热时期,价格部分位会展示成「?」,需要转化成用户能够理解的语音内容。鉴于首位也可能被隐藏,故统一转化成「xx 元以内的形式」。
展示不完整的文本
信息会被脱敏,部分字符会展示成「*」,会都成「星星」,需要将对应文本转化成「星号」。
双十二的 1212 文案
文本内容「1212」会直接朗读成「一千两百一十二」,可以设置为「双十二」或「幺二幺二」。
设置正确的角色
常见的角色有:
- text,让用户知道当前内容是文本
- img,获取焦点后会在 label 后读出「图像」,让用户知道当前内容是图片
- link,获取焦点后会在 label 后读出「链接」,让用户知道点击当前内容会触发页面跳转
- button,获取焦点后会在 label 后读出「按钮」,让用户知道点击当前内容会触发当前页面交互行为
依赖用户的习惯,角色可以提高用户操作的效率,开发者在简单的场景下,不需要刻意补充指导性文案。
追加提示
可以添加 accessibilityHint="提示"
属性来追加一个提示(hint),这个提示内容会在角色之后间隔相对长的一段时间之后读出。
在 VoiceOver 的设置里是可以设置不朗读提示的,请务必将重要信息包含在内容中,提示只作为渐进增强的方案使用。此外,目前在 web 和 Android 场景,没有对应的功能。
VoiceOver Module
除了 Weex 组件上支持的无障碍特性之外,Weex 新增了模块 voice-over
,提供额外的能力。
VoiceOver 的开启/关闭状态
有些场景可能需要在 VoiceOver 开启的时候做特殊处理,可以通过调用 isVoiceOverOn 方法以及监听 WXVoiceOverStatusChanged 事件来获取 VoiceOver 的开启/关闭状态。
例如监控页面在 VoiceOver 开启下的访问量来推算无障碍用户数。
朗读自定义内容
调用 read 方法能够让系统朗读我们需要的内容。
例如常见的 Toast 组件就需要在展示信息的同时,朗读相应内容。
没有标题的页面需要在页面初始化完成之后朗读出页面标题。
使组件获得焦点
focusToElement 方法会尝试使指定元素获得焦点(前提是该组件能够获得焦点)。
常用的场景是为了保证页面初始化结束之后,页面上的第一个结点(一般是页面左上角的第一个组件)能够获得焦点。这个组件往往是导航条上的后退按钮,由于无法获得后退按钮的 ref,此时需要调用 focusToNavigationBack 方法尝试聚焦。
手淘导航条的定制
设置右侧图标的时候指定朗读内容和角色
// navigator.setNavBarRightItem
navigator.setNavBarRightItem({
'aria-label': '分享',
'role': 'button',
icon: 'share',
fromNative: 'true',
iconFont: 'true'
}, (e) => {
alert('click!');
});
}
// navigationBar.setRightItem
navigationBar.setRightItem({
icon: 'https://gw.alicdn.com/tfs/TB1O.XGXOqAXuNjy1XdXXaYcVXa-60-60.png',
'aria-label': '新',
'role':'button'
}
hc.setTBHCConfig 导航中部设置指定朗读内容和角色
会场框架支持在导航条中部配置可以跳转的图片,例如在导航条嵌搜索框。需要额外传入 naviCenterAriaLabel 和 naviCenterRole 来指定朗读内容和角色。例如在导航条嵌搜索框场景,可以设置为
{
"naviCenterAriaLabel": "双十二搜好物",
"naviCenterRole": "link",
}
Rax 开发
组件开发
组件的无障碍开发很重要,可以大幅减少业务的无障碍开发成本,大幅提高业务无障碍表现。同时也面临巨大挑战,特别是交互复杂的组件,面临的问题如下:
- 交互方式需要斟酌,缺少具体的标准,必要时需要邀请用户进行调研
- VoiceOver 手势的局限,转子功能或新的手势对于用户的学习成本都很高
组件开发者需要保证界面组件支持属性透传到容器,目前很多组件无法设置,只能在组件外再包裹一层容器。功能性组件需要考虑无障碍,在必要时预留朗读内容和角色的入参。
退一步,如果组件对无障碍用户过于复杂,可以暂时先屏蔽(不可见或无法获得焦点)。
业务应用开发
业务开发者大部分要做的是透传属性(配置焦点,朗读内容,角色,提示)。需要注意的:
- 约定数据字段的时候预留朗读内容需要的字段,尤其是很多文字被做进图片素材的场景,例如图片资源位,需要运营额外提供资源描述字段
- 尽可能使用组件并收敛组件选择,例如目前有多个途径定制手淘导航条(navigator,navigationBar,hc,WindVane 等),修复一个问题需要挨个修复,且修复成本和难度不可控
- 某些优化点需要权衡额外的开发工作量和收益
写在最后
Weex 和 Rax 团队在 IOS 上的无障碍基础能力已基本完成,下一阶段会重点关注 Rax 组件和 Android。无障碍是一个产品和团队需要共同关注的话题,欢迎大家一起共建,相关疑问和建议可以在钉钉群中进行,也可以前往 aone 反馈。
更多
开启 VoiceOver 测试
从 iOS 11.2 开始,VoiceOver 在中文系统里译为「旁白」。
可以通过以下路径找到 VoiceOver 的开关:「设置」 -> 「通用」 -> 「辅助功能」 -> 「视觉 - VoiceOver」。
也可以调出 Siri(长按 Home 键),说 「VoiceOver」,Siri 会显示入口。
接着说「打开」直接开启
或直接说 「请打开 VoiceOver」开启
还可以说「设置 VoiceOver」直接进入 VoiceOver 的设置界面。
通过辅助功能快捷键快速开启/关闭 VoiceOver
建议通过设置「辅助功能快捷键」的方式便于后续快速开启/关闭,路径为「设置」 -> 「通用」 -> 「辅助功能」 -> 「辅助功能快捷键」。
若只选择了「VoiceOver」,后续连按三次 Home 键则可以快速开启/关闭 VoiceOver。
若选择了多项,连按三次 Home 键会呼出一个菜单
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论