京喜小程序首页无障碍优化实践

avatar
全栈开发工程师 @京东

前言

本文参考 WCAG 2.1WAI-ARIAWeb 可访问性与无障碍最佳实践,在京喜小程序首页无障碍优化开发中,总结了一些“无障碍优化”在小程序端的实践,希望以此推动无障碍在小程序更多地落地。

无障碍

无障碍是什么?

在了解无障碍之前,我们先来了解一些数据:

  • 据中国盲协的最新数据显示,中国目前视障者有 1700 多万,随着老龄化的严重,视障群体有进一步扩大的趋势。
  • 在中国,有着庞大的信息障碍群体,包括:8500 多万残障人士,两亿多老年人,大量认知障碍人士。

障碍群体

无障碍

无障碍 (Accessibility),是指在发展过程中没有阻碍,活动能够顺利进行。从无障碍引申的相关词汇有,无障碍设施、信息无障碍、无障碍交流等等。

信息无障碍

对于信息无障碍,中国互联网协会给出了一个定义:任何人(无论是健全人还是残疾人,无论是年轻人还是老年人)在任何情况下都能平等地、方便地、无障碍地获取信息、利用信息。

以上释义,源自百度百科

无障碍设施

如果看不见、听不见,我们该怎么生活呢?

看不见

在生活中,我们常常会看到一些设施:缘石坡道、盲道、无障碍垂直电梯、无障碍扶手、人行横道的警示信号等等。这些给障碍群体使用的安全设施,就是无障碍设施 (Accessibility Facilities)。无障碍设施主要是为了让障碍群体能够自主、安全、方便地通行和活动,它是障碍群体生活顺畅的重要保证。除物质环境的无障碍设施,无障碍设施还可以扩展到信息和交流的无障碍,比如互联网中的网站设计、网上办事、购物交互等。

无障碍设施

信息无障碍的现状

随着互联网不断发展,互联网应用已经融入到我们生活的各个方面,行动不便的障碍群体则更希望也更需要通过方便的互联网应用获取信息、学习和生活。因此,互联网应用进行无障碍优化,对障碍群体显得尤为重要。

早在 1997 年 2 月,万维网联盟 (W3C) 为了提升网络的无障碍性,成立了网络无障碍推动 (WAI)小组,并制定了一系列的关于网络无障碍的标准、规范、检测表、无障碍的技术,并与世界各地的组织携手合作,在全球范围推动无障碍网络运动。

但至今为止,互联网产品的无障碍优化进展仍然缓慢,很多网站建设和移动端 APP 的开发都还未考虑无障碍优化,即使是通过读屏软件,也很难获取想要的信息。

障碍群体调研

信息无障碍研究会

我们以电商平台购物 APP 为调研对象,同信息无障碍研究会合作做了一个调研。根据收集到的舆情反馈,我们了解到:

在消费降级的当下,低价商品火遍互联网的每个角落,障碍群体是其中需求度最大的人群之一。京喜,作为京东旗下的拼购电商平台,与拼多多和淘宝特价版一样,在障碍人士聚集的论坛和QQ中,有非常多的讨论。用户们对京喜没做无障碍表示遗憾,也期待京喜可以尽快开展无障碍优化,享受低价拼购的乐趣。

根据研究会信息无障碍工程师初步检测,目前影响障碍用户们使用缺陷集中在以下几类中:

  1. 按钮未加标签,用户难以了解对应按钮点按分别会触发哪些功能。
  2. 精简状态不提示或提示不符合障碍用户理解习惯,导致用户无法了解正确的信息,诸如是否已加入购物车等。
  3. 焦点逻辑混乱或没有遵循正确的读屏浏览模式,致使用户不能便捷、清晰地了解界面信息,严重影响操作效率。
  4. 活动信息或弹窗等页面,由于使用大量字绘架构且没有集成无障碍特性,用户无法便捷地参与平台营销活动。

以上几类属于障碍用户能够无障碍使用的基本支撑,部分或完全适配后将能促使 APP 实现较好的无障碍体验。

无障碍优化开发

在了解小程序的无障碍优化之前,首先需要了解 Web 无障碍开发的基础知识,及读屏软件的工作方式。

读屏软件

无障碍访问的关键点 —— 使用屏幕阅读器

移动端 APP 访问无障碍特性,开启读屏模式的设置路径:

  • iOS: 设置 -> 通用 -> 辅助功能 -> 旁白(VoiceOver)
  • 安卓:设置 -> 辅助功能 -> 无障碍 -> TalkBack(不同机型路径可能不一样)

以下是一些主要的 VoiceOver 手势:

  • 轻点:选择并朗读项目。
  • 轻点两下:激活所选项目。
  • 左右轻扫:选择下一项或上一项。
  • 三个手指向上或向下轻扫:滑动屏幕上的列表或区。
  • 双指搓擦:快速来回移动两个手指三次(形成“z”字形)以解除提醒,或者返回上一个屏幕。
  • 更多手势可以查看 :VoiceOver - iPhone 使用手册

安卓的 TalkBack 手势与 VoiceOver 有一些差异,后面还会提到……

WAI-ARIA

WAI-ARIA 通过浏览器把信息暴露给 accessibility APIs (无障碍API),作为读屏软件的信息源。

WAI-ARIA ( Accessible Rich Internet Applications (WAI-ARIA) 1.1) 是一项技术,它可以通过浏览器和一些辅助技术来帮助我们进一步地识别以及实现语义化,这样一来能帮助我们解决问题,也让用户可以了解发生了什么。WAI-ARIA 是 W3C 编写的规范,定义了一组可用于其他元素的 HTML 特性,用于提供额外的语义化以及改善缺乏的可访问性。

以下是规范中三个主要的特性:

  • 角色 —— 定义元素是干什么的。如 role='button' 表示元素是按钮,读屏软件会读作“按钮”、role='searchbox' 表示元素用于搜索,读屏软件会读作"搜索"。
  • 属性 —— 让元素具备更多的意义。如 aria-required='true' 表示元素在表单上是必填的、aria-label='描述文字' 用来给当前元素标签加上描述,用不可视的方式给元素加 label,接受字符串作为参数,读屏软件会将描述文字朗读出来。
  • 状态 —— 用于表达元素当前条件的特殊属性。如 aria-disabled='true' 表示表单禁止输入、aria-hidden='true' 表示元素会被读屏软件忽略。

更多属性可以参考 Using Aria 中的 States and properties,部分属性可能在小程序设置不生效。

更多 role 可以参考 Using Aria 中的 Widget Roles,部分 role 可能在小程序设置不生效。

因此,无障碍优化便可以借助读屏软件,结合 WAI-ARIA 的特性进行开发。互联网应用引入无障碍特性,使得障碍用户可以清晰准确的获取到页面信息,获得更好的产品体验,方便地实现网上办事、购物等。

京喜小程序首页无障碍优化

背景

此前,京喜小程序未进行无障碍优化,障碍群体在读屏软件的辅助下,基本不能使用。这使得平台失去了障碍群体的市场,同时障碍群体也失去了体验京喜小程序平台服务的机会。因此,希望对平台进行无障碍优化,提升平台的可用性、易用性,让障碍群体享受更好的购物体验。

优化方案

产品提供焦点划分规则、朗读规则、阅读顺序,为京喜小程序首页量身定制无障碍优化方案。内部方案,这里就不透露了。(想了解的话,来投一波简历啊~)

开发实现

目前小程序官方已经支持无障碍访问特性,用户在读屏模式下可以体验无障碍访问。

开发细则

DOM 顺序很重要

读屏软件在读屏时默认按照 DOM 的顺序朗读。 如果 DOM 的顺序与内容的语义顺序不一致,会使得内容难以理解。例如首页中的商品瀑布流,按左右两列布局:

首页 feeds 左右两栏

在开发过程中应尽量避免使用会影响到 DOM 视觉顺序的样式,如果无法避免,需要手动设置 tabIndex 属性,告知读屏软件正确的内容顺序。

非文本元素增加描述和角色属性

通过给非文本元素增加描述和角色属性,元素的内容就可以被读屏软件清晰准确地朗读。

  • 图像可使用 alt 属性描述图像内容,读屏软件会根据 alt 中的内容朗读出 “描述图像内容 图像”
  • view 本身是无语义的,可以给元素增加 aria-rolearia-label 属性。 读屏软件会朗读出 “label 描述内容 + role 类型”

整块元素读取

一个元素可能由很多子元素组成。在无障碍模式下,读屏软件只能分别聚焦子元素,单独将每个子元素信息读出来。障碍用户在读屏软件的辅助下,获取到的都是元素零零碎碎的信息,这样的体验很不友好。

icon-商品图

因此,在无障碍优化过程中,可以将元素当作按钮整块朗读,将子元素的信息整合作为描述,并尽量精简描述内容,缩短朗读文案的时间。

隐藏元素读取

如果不希望部分内容被读出来,可以使用 aria-hidden='true' 来声明,这样读屏时就会忽略这些元素。

 <Text aria-hidden='true'>读屏时会忽略这行文本</Text>

在无障碍模式下,这个属性可用来隐藏辅助作用不大或是具有干扰性的内容。

场景实现

非文本元素读取

首页头部中京喜 Logo 和文字是一整张图片。聚焦后,读屏软件默认会读成图像,无法将图片中的文字朗读出来。这样的无障碍体验是非常差的。

惊喜Logo

在这个场景下,可通过给 Logo 图片增加描述来进行无障碍优化。

 <View className='index__main'>
    <View className='index__logo' aria-role='text' aria-label='京喜' />
    <View className='index__title'>京东旗下社交电商平台</View>
 </View>

类似的还有关闭按钮、返回顶部按钮、菜单栏按钮……

关闭按钮、返回顶部按钮、菜单栏按钮

<View
   className='back-top'
   aria-role='button'
   aria-label='返回顶部'
/>

搜索框读取

首页搜索框聚焦后,读屏软件默认会将搜索框中的暗纹读出来。但是障碍用户并不能明显的感知到搜索框元素。

搜索框

在这个场景下,可以通过给搜索框增加角色属性来进行无障碍优化。

<View aria-role='searchbox'>
    <SearchBar />
</View>

轮播图读取

轮播图由多个子元素组成,但点击为整块点击,且每个子元素都是图片,读屏软件无法让用户清晰感知元素的含义。

轮播图

在这样的场景下,可以给每一个子元素标签增加描述,读屏软件就可以识别到子元素了。

<View className='banner'>
    <Swiper>
        <SwiperItem aria-role='text' aria-label='活动推荐1'>活动1</SwiperItem>
        <SwiperItem aria-role='text' aria-label='活动推荐2'>活动2</SwiperItem>
        <SwiperItem aria-role='text' aria-label='活动推荐3'>活动3</SwiperItem>
        <SwiperItem aria-role='text' aria-label='活动推荐4'>活动4</SwiperItem>
    </Swiper>
</View>

但这样的无障碍优化在安卓手机上体验并不友好。

当障碍用户聚焦到轮播图后,读屏软件将子元素的描述朗读读来。轮播图继续轮播,焦点索引却不会随轮播状态自动更新,而是跟随当前子元素滑动消失在屏幕中。若要获取更新后的轮播信息,需要重新聚焦。

轮播图

在这样的场景下,建议在轮播图的最外层增加描述,将整块内容当作按钮处理,让障碍用户清楚这是整体点击的按钮。

<View className='banner' aria-role='button' aria-label='活动推荐,共4个'>
    <Swiper>
        <SwiperItem>活动1</SwiperItem>
        <SwiperItem>活动2</SwiperItem>
        <SwiperItem>活动3</SwiperItem>
        <SwiperItem>活动4</SwiperItem>
    </Swiper>
</View>

商品卡片读取

商品卡片由多个子元素组成,读屏软件会将聚焦的子元素(商品图、名字、价格、利益点等)一个个的读出来。

商品图

但单独读出每个子元素,不便于障碍用户理解商品卡片的完整含义。

类似这样的场景,可以将商品卡片当作一个按钮整块处理。在商品卡片最外层标签加上 aria-role='button',还可以通过 aria-label 标签,将商品信息进行整合,精简描述,缩短商品名字的朗读时间,让障碍用户获得更好的体验。

隐藏元素读取

上文提到商品卡片的无障碍优化可通过 aria-role='button'aria-label 来实现。理想情况下,当障碍用户聚焦到商品卡片,读屏软件将整合的商品信息朗读出来,并提示是按钮类型。

但实际情况并非如此。当障碍用户在安卓手机上聚焦后,读屏软件不仅会将整合的商品信息和 role 朗读出来,还会将商品卡片子元素的文本内容朗读出来。(后文会提到 iOS 的表现)

为了避免商品信息重复朗读,可以在元素文本标签上加上 aria-hidden='true' ,隐藏子元素文本描述,让障碍用户能够获取到清晰简洁的商品信息。

<View aria-role='button' aria-label='商品整合信息'>
    <View aria-hidden='true'>
        <Image className='goods__img' src='https://img20.360buyimg.com/ling/jfs/t1/129045/25/12798/233574/5f61ffdbE248117d0/52fd1d1ee42b4443.png' lazyLoad />
        <View className='goods__info'>商品信息…</View>
    </View>
</View>

iOS 和安卓端的差异

滑屏手势差异

安卓:双指滑动,根据手势自适应滑动;

iOS:三指滑动,一屏一屏分页滑动。

轮播图焦点差异

轮播图

安卓:焦点位置会跟随子元素滑动消失;

iOS:焦点位置固定不变,不会随子元素滑动而消失。

价格读取差异

¥259.2

由于整数部分和小数部分字体大小不同,价格文本是用多个标签实现的。

<View>
    &yen;
    <Text>259</Text>
    <Text>.2</Text>
</View>

安卓:完整朗读 “259.2元”;

iOS:单独朗读单位、整数、小数,并且会将 “¥” 读作“美元符号”。

aria-role='button' 读取差异

安卓:读作“描述+按钮+子元素文本描述”,需借助 aria-hidden='true' 隐藏子元素文本描述,避免信息重复朗读。

iOS:有两种情况。

  • 如果标签同时设置了 aria-label ,则读作“描述 按钮”,不重复朗读子元素文本。
  • 如果标签仅设置了 aria-role='button' ,会继续识别子元素文本,读作“描述+按钮+子元素文本描述”。为避免重复朗读,也需要给子元素加上 aria-hidden='true'

小程序无障碍展望

小程序基础库自 2.7.1 起,支持部分 ARIA 标签,但是仍有部分属性和 role 在小程序中不生效,希望未来可以支持所有的 ARIA 标签,给障碍用户带来更好的体验。

另外,小程序目前还没有相关 API 支持识别用户手机是否开启无障碍(读屏)模式(原生 APP 可以通过相关 API识别)。如果能预知用户手机开启了无障碍模式,就可以通过动态控制前端模块展示,从而更好的隐藏无用信息、排除干扰信息(浮层弹窗、动画等)。在启无障碍模式下,设置数据埋点上报,还可以为障碍用户提供更好的体验。

幕帘

希望微信小程序能尽快加强对无障碍优化开发的支持力度,让障碍群体能够享受信息化所带来的成果,享受便捷美好的生活。

无障碍体验

手机开启读屏模式,扫码二维码体验:

京喜小程序二维码

结语

京喜小程序首页无障碍优化上线后,我们对调研的障碍群体进行了回访,并且得到了不错的体验反馈。

这是我们在小程序无障碍优化上迈出的第一步,要获得更好的小程序无障碍访问体验还有很长一段路要走……

希望此次小程序无障碍优化实践,能让障碍群体享受互联网应用所带来的便利,更好的享受生活。