【IT之家学院】改善视障用户的网页体验 —— 替代文本的那些事儿

欢迎来到 IT 之家学院,这里是无障碍实验室。时隔一月,再次与大家见面,我感到非常愉快。今天,我们来一起探讨替代文本的相关问题。

长久以来,视障用户都是在屏幕阅读器的辅助下,才得以赶上互联网大潮,进而享受到互联网带来的红利。这一切都建立在互联网产品与屏幕阅读器具有良好兼容性的基础上。体现最明显的一点便是:产品各功能性组件应确保具有可读性较高的文本型标签。如若不然,依托文本合成语音的屏幕阅读器也只好表示爱莫能助了,只能干巴巴的读出“未加标签”来安慰一下你那孤寂的灵魂。

互联网的早期时代,受限于网络传输能力,绝大多数产品都十分体面地通过文字来呈现内容,因此无障碍问题暴露得并不明显。而伴随互联网基础建设的日趋完善,网络迈进高速发展的快车道,功能堆砌和设计花哨有了先决条件,一场场美化运动掀起一阵阵“血雨腥风”,在普通用户看来顶多算是有碍观瞻,但对于视障用户而言,那可真就是叫苦不迭了,他们只能苦哈哈地听着一串又一串的“未加标签”勉强过活。

不过,任何事物的发展,无外乎从低级快速迈入高级,再由高级逐渐趋于完善,无障碍同样遵循这个原则。在经历了早期的垦荒时代后,终于迎来了希望的曙光。就在 2020 年 12 月 24 日,工业和信息化部下发了《互联网应用适老化及无障碍改造专项行动方案》,方案的总体要求强调:针对视障人士,应解决按钮标签和图片信息不可读的问题。

其中,按钮标签和图片信息均可通过替代文本的形式添加,同时也不会影响现有的视觉体验。因此,为了让更多的开发者能充分理解这一特性,我们特此撰写了这篇文章,希望能对大家带来些许帮助。

什么是替代文本?

替代文本,一种用于补充或替代非文本内容的文字性说明,可编程式地提供或从现有文本中引用,通常用于为非文本控件创建标签,或为非装饰性内容提供简要描述,具有十分广泛的应用场景。

几乎所有的语言都支持替代文本。例如,HTML 规定 img 标签必须提供的 alt 属性,它可在浏览器无法显示图像时输出文字信息,更重要的,这些文字信息有助于屏幕阅读器用户清晰直观地了解图像内容。又如为元素提供额外信息的 title 属性,当元素获得鼠标指针时弹出工具提示,但从某种角度上说,它并不能作为首选的文本替代方案。

事实上,由 HTML 5 原生控件构建的页面,其无障碍体验是非常优秀的。因其支持自定义控件而具有丰富的扩展性,广受开发者的认可。W3C 为了使自定义控件能获得与 HTML 5 原生控件相同的无障碍体验,加强自定义控件的语义化支持,制定了 WAI-ARIA 技术规范。通过该项技术规范实施页面开发,能最大限度地保障各类障碍人群的无障碍体验。

在 WAI-ARIA 中,通过 aria-labelaria-labelledby 属性为元素创建标签,从而达到替代文本的目的。“标签”的信息应当是简短而明了的,它是用户最先获取到的控件信息,有着超然的地位;当标签无法准确传达控件的信息时,开发者可提供 aria-descriptionaria-describedby 属性,为用户提供更为详细的内容描述。

应用 aria-label 创立替代文本

控件的标签不为文本型,或标签的文本没有准确传达控件的目的,可使用替代文本提供更为明确的标签。例如,一个点击发送“滑稽”表情的按钮,它的标签由 emoji 表情组合而成,就像这样:

<button>🏵🐤</button>

绝大多数的屏幕阅读器支持 emoji 表情的朗读,但这并不意味着所有用户能理解这个组合表情。因此,我们通过替代文本来告知用户,它具有“滑稽”的含义。

<button aria-label="滑稽">🏵🐤</button>

如你所见,aria-label 属性中填充的字符串即为替代文本。在本例中,屏幕阅读器将朗读为“滑稽 按钮”,及 aria-label 的值与元素类型被读出,控件的 innerText 则被忽略。所以,我们可以很快得出,当 aria-labelinnerText 同时存在时,aria-label 的优先级高于 innerText

当你考虑好一切,决定使用 aria-label 时,请确保填写了恰当的值。切忌将其设为空值,这虽然不影响屏幕阅读器获取 innerText 的信息,但并不能保障所有的屏幕阅读器都能良好兼容。尤为重要的,控件中 innerText 已经明确传达含义了的,无需额外提供替代文本,除非开发者认为替代文本具有更精准的表达。

通过 aria-labelledby 关联标签

从 aria-labelledby 这一属性名称上不难察觉,该属性可用于为控件关联替代文本。换言之,dom 中若存在可用的文本,即可通过该属性引用文本的元素 id ,使其作为控件的替代文本。令人赞叹的是,该属性还可关联多个元素 id ,而你仅需将元素 id 按从左到右的顺序依次排列,并用空格分割,aria-labelledby 将逐一创建关联,并按照你规定的顺序朗读。

例如,一个支持输入页码后跳转页面的编辑框,它所拥有的标签被拆分成了若干个元素,我们就可通过 aria-labelledby 这样的神仙属性来关联,而不再需要费劲巴力的通过 aria-label 手动填写了。

<span id="numero"> 第 </span>
<input type="text" id="input" value="1" 
aria-labelledby="numero input page total" />
<span id="page"> 页 </span>
<span id="total"> 共 5 页 </span>

当用户使用 tab 键聚焦至该编辑框时,屏幕阅读器将朗读为“第 1 页 共 5 页 可编辑文本 1”。显然,“可编辑文本”前的内容是我们关联的标签,之后为输入字段的 value 属性值。如果没有关联标签,这样的编辑框在屏幕阅读器下会表现得十分糟糕,如何朗读完全取决于浏览器与屏幕阅读器的配合了。

细心的你或许已经发现,我们将 input 的元素 id 一并加入到 aria-labelledby 中,还指定了它的出场顺序,也正如你所看到的,value 的初始值被作为标签的一部分。这样做的好处在于,视障用户编辑字段时,能在标签上直接反馈输入结果,进一步加强了标签的语义化表达。

需要引起重视的是,aria-labelledby 遵循与 aria-label 同样的原则,及确保关联文本具有简明扼要的标签意义。所不同的是,aria-labelledby 的优先级高于 aria-label ,当二者同时存在时,仅 aria-labelledby 生效,W3C 也更推崇使用 aria-labelledby 。当 DOM 中含有可用文本时,请通过 aria-labelledby 属性关联它,而并非手动填写 aria-label ,除非开发者认为后者的表现更为优异。

更易于理解的描述性文本

在非常痛苦的阅读了上述这些味同嚼蜡般的文字后,渐渐地拼凑出了一个脉络,并决定改造自己维护的页面,但沮丧的发现,仍有极个别顽固的组件无法准确传达含义,于是有人可能打算顺着网线摸过来给笔者一顿老拳,我劝你想开些,毕竟本文还没结束,中途下车的拒不退票。

在经过上述步骤,仍然无法精准传达控件含义的,就可祭出终极大法,及 aria-description aria-describedby 属性。结合此前内容,基本不再需要笔者展开叙述了。aria-descriptionaria-label 用法一致,可供开发者自定义的创建描述信息;aria-describedby 则与 aria-labelledby 对应,可从 dom 中关联可用文本。同样地,描述性文本也具有优先级,aria-describedby 的优先级高于 aria-description ,因此 W3C 推荐使用 aria-describedby

事实上,我们只要类比 HTML 即可轻松的理解这些属性。aria-labelaria-labelledby 更接近于元素的 innerText,具有标签的表现形式;而 aria-descriptionaria-describedby 类似于 HTML 的 title 属性,有所差异的,aria-descriptionaria-describedby 的文本描述不具有 title 属性的工具提示浮窗。

这仍然是一个发送“滑稽”表情的按钮,只不过,我们加入了描述性文本,使用户能更明确该按钮的目的。

<button aria-label="滑稽" aria-description=" 点击以发送“滑稽”表情 ">🏵🐤</button>

此时,屏幕阅读器将朗读为“滑稽 按钮 点击以发送‘滑稽’表情”,目的和作用表达得都非常明确。但非常遗憾的是,该属性并没有在当前流行的 WAI-ARIA 版本中定义,就目前而言,仅 chromium 和 Firefox 浏览器具有良好的支持,这也是更推荐使用 aria-describedby 属性的根本原因吧。

仍然是这个页码编辑框,现在,加入了 aria-describedby 属性,使它的易用性迈上了一个新的台阶。

<span id="pagination"> 页码:</span>
<span id="numero"> 第 </span>
<input type="text" id="input" 
       value="2" 
       aria-labelledby="pagination" 
       aria-describedby="numero input page total" />
<span id="page"> 页 </span>
<span id="total"> 共 5 页 </span>

经过上述简单修改,该编辑框在屏幕阅读器下朗读为“页码: 可编辑文本 2 第 2 页 共 5 页”,啧啧,多么明确的表达。

写在文末

从本质上讲,笔者是一个嘴笨笔拙的人,拉拉杂杂的堆砌了这些文字,在通读全文后,若确有疑惑存在的,欢迎在评论区留言,笔者会在评论区领教各位的刀法绝伦。

此后,笔者争取以月更一篇的频率,持续撰写此类题材的文章。一来借助 IT 之家的声望,向大众普及一波信息无障碍;二来便于广大开发者从这个专题中能够汲取到相关经验;第三,也是最重要的,这将是笔者个人的一次技术总结,也磨练我的写作能力吧。望大家一如既往的支持我们,支持无障碍,谢谢!

ozabc