如何提高Web可访问性

发布于 大漠

A11Y 101系列构建可访问性应用的2W1H中和大家聊了构建Web可访问性的重要性。构建可访问的Web是Web开发的重要组成部分之一,构建出一个具有可访问性的Web页面或应用程序能确保有障碍的人士能够平等的访问Web,使他们能够享有访问Web的权力,也能让他们更好的融入于社会,使其生活变得更有意义。这也是Web开发者应该担当的责任。在这篇文章中,将和大家聊聊,构建Web可访问性的检查清单。希望能帮助更多的开发者能更容易开发出更具可访问性的Web页面或Web应用。

为什么要关心Web可访问性

在《构建可访问性应用的2W1H》中花了整整的一章的篇幅和大家聊了一下Web可访问性的重要性。在这里我想再次重着提出的是 不管是Web开发人员,还是设计师或者PD,都应该确保自己的产品具有较好的可访问性,能让有障碍的人士可以平等的享受Web提供的服务。而且构建可访问性不应该是工作流程中最后的一个环节,而应该是Web开发过程的早期环节。其中的原因有很多,这里简要的列出几点:

  • 在许多地区,特别是参与国际业务开发的,更应该让自己开发的产品具有可访问性。在许多地区对于可访问性是有一定法律约束的,比如美国、欧盟、英国、以色列和日本,就有相关的法律条文,明确要求Web应该要让有障碍人士可以正确的访问。如果无法满足这样的要求,很有可能会被起诉,说你歧视残障人士(甚至不是残障人士,只是访问Web有障碍的人士)。在过去的一年,美国就有近2235个网站被联邦法院起诉过。
  • 易访问的Web往往在编码上也更好,更健壮,对于SEO(搜索引擎)也更友好
  • 易访问的Web对于有障碍的人士来说更易于使用,从而带来更大的满意度和转化率
  • 可访问性较差的Web,对于业务来说也更不利。在过去的一年中,英国的一项调查发现,超过近400万因为Web应用可访问性较差而放弃从该应用上购买自己所需要的商品
  • 可访问性较差的Web,实际上是主动的拒绝了潜在客户,这样做总是不好的

其实还有更多的原因,具体的可以阅读《构建可访问性应用的2W1H》一文。

共同的标准和问题

幸运的是,开发可访问Web应用时有很多规范可以参照,比如W3C提供的WCAG规范(Web内容可访问性指南)。该规范提供了各种标准以及告诉开发者如何能更好的开发一个更具可访问性的Web页面或应用。在构建可访问Web网站或应用除了WCAG规范可参阅之外,还有很多相关的规范或条文可参阅,比如:

不过,这些规范是一本冗长、枯燥和技术性很强的读物,所以对于很多开发者而言是件痛苦的事情。接下来将会给大家罗列一些列表,这样可以让开发者更好的了解构建可访问性Web时需要检测哪些列表项,从而获得最大的收益。当然这也并不是所有清单,但这是最常见的一个清单,有障碍人士说这些是影响他们访问Web最主要的障碍。针对每一项,也会向大家提供相应的建议。

Click-Away Pound对网上商店做过相应的调查,旨在探索残障人士的网上购物体验,在这份调查报告中整理出最可能阻碍残障人士在网上商店购物的几个项:

  • 内容太多的页面占 66%
  • 验证码(reCAPTCHA)测试占 59%
  • 易读性差(对比度,文本布局)占 56%
  • 移动图像和图形的干扰点 53%
  • 链接信息差占 59%(屏幕阅读器用户为 77%
  • 表单填充占 56%

上面是访问网上商店障碍有障碍人士访问的最常见的几个项。2019年8月份WebAIM提供了另一份报告,该报告针对更广泛的Web网站(近100万网站的主页)做过分析,其中 **98%**的页面至少有一个错误。其中最为常见的是:

  • 文本对比度低占 86.1%
  • 图像缺少替代文本占 67.9%
  • 空链接占 58.9%
  • 表单输入控件(<input>)缺少标签(<label>)占 53.2%
  • 文档缺少语言类型占 30.5%

另外在2019年Web Almanac也出具了一份有关于Web可访问性相关的报告,其中列出的项和WebAIM提供的报告相似,具体的这里不列出,感兴趣的可以点击这里阅读

如何提高网站的可访问性

很多时候,很多人都认为,提高Web的可访问性只是开发人员应该具备的技能,也是开发人员应该去做的事情。事实并非如此,很多时候一些设计,或者说一些文案也会给Web的可访问性提供障碍。比如下面提到的这些。

内容过多

使用标题或项目列表将内容分成几个部分,尽可能使用简单的语言

众所周知,可选择性越多,越能做出正确的选择。内容过多也同样的,会让人很难受。把内容精简到最基本的部分是一项耗时的工作,正如马克吐温所说:

因为我没有时间写一封短信,所以我写了一封长信。

@Michael J. Metts@Andy Welfle最近共同写了一篇《可访问的书写标准》 ,其中建议:

不管是从视觉还是听觉出发,人们都希望能够浏览大段文字,所以用标题、段落等来设计是组织长篇内容的最佳实践,而且这对于长篇大论来说也是非常重要的。

所以说,在我们构建的Web页面上应该:

  • 在一个Web页面上只有(或仅有)一个<h1>
  • 使用副标题,它可以为视力正常的用户分解长篇的内容,而对于屏幕阅读器等辅助技术的用户可以使用快捷键在标题之间跳转,或从标题结构中获得内容
  • 不要跳过某个级别的标题,比如说,如果你使用了<h3>标题,请确保它前面有<h2>标题
  • 在HTML中正确的使用项目列表符号,比如正确的使用<ol>(或<ul>)以及<li>,屏幕阅读器等辅助技术可以更好的识别,并允许用户跳过它们

在A11Y的检查清单中也有相应的描述:

从Web可访问性方面来说,Web在标题方面的设计可以起到的作用:

标题元素h1~h6有助于将页面的内容分解成相关的 **“块”**信息

在使用标题时应该考虑:

  • 标题元素构建成文档大纲,更多的时候不应该仅纯粹从视觉设计来考虑
  • <h1>元素应该用于传达页面或视图的最高目标(一级标题),不要将<h1>元素用于在页面或视图之间共他的的标题
  • 标题元素的顺序应该根据内容的级别一级一级往下(h1~h6),比如说,<h4>不应该出现在<h3>之前
  • 标题元素不应该随间跳过,比如从<h2><h4>之间就不能跳过<h3>。如果为了特定的视觉效果而跳过标题级别,那么可以使用CSS来实现

对于屏幕阅读器等辅助技术而言,屏幕阅读器必须得到指示,以了解哪些内容是最重要的,以及应该如何组织这些内容。标题为屏幕阅读器提供这些信息,帮助视力受损的用户更快地浏览你的内容。

对于列表而言,在构建内容的时候可以以分组的形式告诉用户。比如使用列表元素<ol><ul><dl>。比如下面这样的一个示例:

这样一来,格式化列表为屏幕阅读器提供了如何组织内容相关的信息。

有关于这方面更多的介绍还可以阅读:

除了结构上能带来更好的可访问性之外,在语言的精减上也可以。2010年美国律师@Sean Flammer做过这样的一项实验。他要求800名巡回法庭法官要么站在传统的“法律术语”一边,要么站在他所说的“简单术语”一边。从实验结果来看,有近66%的评委更喜欢简单术语,而这种喜好和他们的年龄以及背景并无关系。

这样的实验同样适合于Web可访问性的构建中。比如在英文中有很多词语是缩写的,比如星期、月份或是一些专业术语。在构建Web可访问性方面,不太建议在内容中使用这些简写的术语,即使要使用,也应该在HTML上做一些优化,比如可访问性方面的一些专业术语就有很多简写的,拿WCAG来说,它就是“Web Content Accessibility Guidelines”首字母简写。如果你在Web模板中的话,可以借助<abbr>标签来构建:

<abbr title="Web content accessibility guidelines">WCAG</abbr>

除了<abbr>这样的HTML标签之外,还可以使用其他的标签,比如span

<span title="Web content accessibility guidelines">WCAG</span>

简单地说,我们应该尽可能的避免在内容中使用简写的术语。有关于这方面更详细的介绍可以阅读@Colin Lieberman的《The Accessibility Hat Trick: Getting Abbreviations Right》一文。

验证码(ReCAPTCHA)

不要为了节省开发人员的时间而让你的用户无法完成任务

在很多Web应用中会用到验证码相关的技术。特别是在表单运用中使用的更为频繁,比如在登录的时候为了验证不是机器人在操作,会有一些复杂的验证界面,如下图所示:

甚至还有更为复杂交互图形验证码,比如B站的登录验证:

从技术上而言,更具复杂交互的图形验证在某种程度上来说,可以避免很多作弊的行为(比如机器人),但这些图形验证(特别是具有复杂交互的图形验证)对于Web可访问性来说是存在极大问题的。比如一些视力有障碍的用户,它可能看不清楚(甚至是看不到)如何才能正确的将图拼出来,满足验证码的需求。

现在很多Web网站或应用中,基本上弃用了摇摆不定的字母风格的验证码(reCAPTCHA),新版本的验证码更多的是像上图那样具有复杂交互的拼图验证码,当然也有被称为我不是机器人复选框的验证码(No CAPTCHA reCAPTCHA),如下图所示:

这样的验证码要求用户对复选框进行操作(选中或不选中),来确认操作的人不是机器人,并使用相应的规则来给用户打分。如果通过,则不需要进行一步的交互。如果失败了,需要进一步的往下操作。比如像下图这样,让用户选择橙色的图像:

请记,要求用户点击所有带有比如小汽车或街道标记的图片来满足验证码的要求,这样的规则并不一定是国际标准。正如@Terence Eden所写,验证码不能证明你是人类,它只能证明你是美国人

最具可访问的reCAPTCHA形多是 reCAPTCHA 第三版本,它不需要用户交互,但是需要你做更多的工作来处理测试失败的访问:

它是一个纯粹的JavaScript API,返回一个分数,使你能够在你的站点上下文中采取行动:例如需要额外的身份验证、向审核人员发送帖子或者对可能正在抓取内容的机器人进行节流。

有关于这方面更多的介绍还可以阅读:

可读性

确保文本有足够的对比度,增强Web的可读性,尽可能避免不合理性。

在Web中构建易读到可读性需要做的事情很多,在CSS中有很多属性可以帮助开发者能更好的构建可读的文本。有关于这方面的内容,曾在《编写CSS时要考虑可访问性》一文中有过很详细的阐述。

在这里着重提几点。

首先需要确保充足的对比性,即文本和背景之间颜色对比度(饱和度)。在Web的可读性方面,文本和背景之间的对比度很差是阻碍构建可读性Web最大的障碍之一。WCAG标准准则在这方面有过详细的规则,规范中要求对比度至少为 4.5:1,除非大型文本或大型文本图像的对比度至少为 3:1

正如上图所示,不同的标准级别AAAAAA在颜色对比度上标准是有所差异的。有关于这方面更多的介绍,可以阅读:

其次,在构建像英文这样的Web网站或应用时,建议不要有全大写的标题。有证据表明,因为大写字母的高度都是一样的,所以我们无法识别普通单词的形状,所以它们更难读。此外,一些屏幕阅读器会将全大写的字母当作缩定,比如像WCAG,BBC等。即使在视觉上要使用全大写的字母,那也应该在HTML中使用正常的书写方式,然而再使用CSS的样式text-transform: uppercase来做处理。这样更利于避免屏幕阅读器等辅助技术将全大写的字母当作缩略词来朗读。

文本排版本方向对于Web可读性也有一定的影响,我们普遍看到的排版方式都是ltr(Left-To-Right)。但如果你负责的业务有像阿拉伯语或希伯来语的话,那么其排版方式就是rtl(Right-To-Left)。不同的排版方式,选用的字体对于阅读性也有相关的影响,如果字体选择不好的话,会让有阅读障碍的人更难阅读。就此方面,英国朗读协会就英文字体的选择有过相应的建议

使用无衬线字体(sans serif),比如ArialComic Sans,因为字母看起来不那么拥挤。另外也提供相应的备选字体,比如Verdana, Tahoma, Century Gothic, Trebuchet, Calibri, Open Sans

有关于针对不同的语种提供不同的排版方式等相关的细节可以阅读《Web中向左向右》一文,从该文中你可以了解到更详尽的内容和相关细节。

分散注意力的图像或媒体对象

允许用户停止任何移动,尊重用户在操作系统上的设置,比如不播放动效或视频

有一些网站,特别是一些网上购物的网站,上面有一些类似牛皮藓的广告,不停的在闪动或移动,并且关闭之后又会不断的加载新的,更多的广告出来。这样的方式对于有障碍的人士来说是致命的体验,甚至对于那些存有智力障碍的用户来说,更是如此。

WCAG规范对于Web上任何可移动、闪烁或滚播的信息等应该给用户提供相应的机制,并做出过相应规范描述。针对于这些场景,开发者应该提供可以让用户暂停、停止或隐藏它。

这样做的主要原因是,这些可移动元素、闪烁以及滚播的信息对于用户来说会影响他们的注意力。其中移动和闪烁也会引起癫痫,所以WCAG规范中就要求过任何闪烁内容在1s内不应该超过3次的闪动

时至今日,CSS媒体查询模块提供了一些新的特性,这些新的特性在很大程度上是用来改善用户体验的,特别是Web的可访问性方面,比如说尊重用户的喜好。比如说,用户开启了减少运动的喜好:

开发者可以使用prefers-reduced-motion媒体查询对页面上可移动的元素做出相应的处理。比如说,不让元素具有动效:

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001s !important;
        transition-duration: 0.001s !important;
    }
}

比如说,仅让页面上某个元素有动效:

@media (prefers-reduced-motion: no-preference) {
    button {
        animation: vibrate 0.3s linear infinite both;
    }
}

除此之外,还有其他有意思的媒体查询特性,就比如说prefers-color-scheme吧,可以根据用户的喜好来开启暗黑模式下使用不同的色系:

有关于这方面更多的介绍,还可以阅读《CSS媒体查询新特性》一文。如果你对Web的暗黑模式感兴趣的话,可以花点时间阅读下面几篇文章:

缺少上下文信息的链接

给链接提供更详细的上下文信息,让链接更易于识别。如果一个链接要在新的标签或窗口打开,应该告诉用户。

Web中的链接如果没有上下文相关的信息,对于Web可访问性来说是比较糟糕的。而且很多Web页面或应用上都有这样的通病,比如说使用一个空链接(没有任何描述信息),好一点的会有“更多”这样的信息。但这样没有较好的方式来区分它们。解决这个问题最简单的方法就是给链接添加上下文信息,即使为了满足视觉上的需要,不能给链接添加详尽的文案,我们也应该通过其他的技术手段来处理,比如在链接标签上添加titlearia-labelaria-labelledbyaria-describedby。比如:

<!-- HTML -->
<a href="#" aria-label="Read more: Joomla Group 2 - President election results">Read more</a>
<a href="#" aria-labelledby="foo">Read more</a>
<a href="#" aria-describedby="foo">Read more</a>
<p id="foo">Read more: Joomla Group 2 - President election results</p>

这样做是因为像屏幕阅读器这样的辅助技术可以获得aria-label中指定的文本信息,W3C也建议将aria-label中使用的文本与链接中使用的文本一起使用,这样可以让用户之间保持一致的通信。另外,也有要title中给链接添加描述文本:

<a href="#" title="click here to read more about the election results">Read more></a>

但是,我不建议这么做。大多数屏幕阅读器对于title的识别较差,那是因为早期为了给Web做SEO,开发人员常常在title中添加便于SEO能识别的关键词,因此很多屏幕阅读器就禁用了title

就Web上的链接而言,除了链接的文本会给可访问性造成糟糕的体验之外,还有外观上也会有相应的影响。简单地说,我们应该让链接看起来更像链接。在默认情况之下,浏览器会对链接添加下划线。就体验上来说,我们最好不要改变这一切,即使为了满足视觉上的需求,必须去除链接的下划线,那么我们应该从别的方面来增强对链接的识别。比如说给链接文添加较强的颜色对比度(相对于非链接文本更明显),另外给链接添加一些指示器,比如说获得焦点,有不同的样式。

就这一点来说,特别是现代Web中,很多时候链接和按钮都无法让用户区分。

而且社区上有关于这方面的讨论也很多,如果你感兴趣的话,可以阅读《它是按钮还是链接?》一文。

就链接和按钮来说,他们有着一个最明显的交互行为的差异,链接会将用户带到新的一个页面。如果<a>标签中显式的设置了target="_blank"的话,会将在一个新的标签(浏览器的新Tab标签)或新窗口,这样的操作可能会让访问者感到困惑,特别是当页面上只有一些链接这么做了。如果必须这样做的话,则应该在链接文本中或在ARIA的一些属性(比如aria-label)中向用户发出警告。比如像下面这样:

<a href='#' target='_blank' aria-label='Opens in new window'>open</a>

另外就是,链接并不一定是全部链接到一个新的页面,有的时候会链接到文件(比如PDF或视频)。对于这样的场景,我们应该在链接文本中告诉用户。不要相关信息隐藏在aria-label中,因为这对很多有视力障碍的用户来说很有用(比如说,有些手机不能打开.docx格式的文件)。另外,如果文件很大,还需要考虑提醒用户将会打开一个很大的文件,或者会下载一个大型文件(比如视频)。毕竟有些用户是不希望无意的误点击,造成流量的浪费。另外一个比较好的做法是在<a>链接中添加download属性,这样做可以让浏览打开操作系统本地文件下载对话框。比如:

<a href="big-report.pdf" download>Annual report (PDF, 240 MB)</a>

未设置焦点样式

给可聚焦元素设置焦点样式是为了确保键盘用户总是能看到他们当前关注的地方。

在HTML中有很多元素是可聚焦元素,浏览器对这些可聚焦元素都会有一定的默认样式。而我们的用户群中有一些用户可以是重度依赖于键盘操作的或者不得不依赖键盘访问Web的。对于这些用户群体来说,焦点样式对他们来讲是很重要的,因为焦点样式能够告诉用户他们现在处理什么位置。

然而,有些人认为这是不美观的(特别是在视觉设计师的眼中,他们是无法接受的,因为直接影响到他们的作品)。虽然默认的焦点样式不太美观,但我们可以通过CSS给可聚集元素的:focus状态下设计一个更美的外观,既能满足Web可访问性的需要,又能让视觉设计师接受。

另外,CSS提供了另一个属性:focus-visible,它可以只让键盘操作获得焦点时有焦点样式,对于鼠标操作不会有焦点样式。@Patrick H. Lauke在他的教程《:focus-visible and backwards compatibility》中对于焦点样式的使用提出下面这样的建议:

button:focus { 
    /* some exciting button focus styles */ 
}
button:focus:not(:focus-visible) {
    /* undo all the above focused button styles
    if the button has focus but the browser wouldn't normally
    show default focus styles */
}
button:focus-visible { 
    /* some even *more* exciting button focus styles */ 
}

有关于这方面更多的介绍,还可以阅读下面这些文章:

表单填充

表单是Web中很常用的控件,也是Web中非常重要的一部分,特别是对于像网上购物的网站,表单就更重要了。但是要设计出好用的表单就不是件易事了,特别是对于那些存在障碍的用户群体来说,不好用的表单更难于为他们提供服务,甚至直接影响他们的使用。

作为Web开发人员来说,都清楚的知道,有些表单控件是很难用CSS来进行美化的,而为了更好的满足设计的需求,让表单的UI看上去更好看,开发人员会采用非表单控件元素(HTML的其他元素)来自定义表单控件。这样做,虽然在UI上看上去好看,但是在可访问性方面就差了,对于有障碍的人士填充表单就更痛苦了,甚至都很难,很好的完成整个表单的填充。

在《聊聊Web中的下拉选项的事情》一文中我们就有聊过自定义下拉选择框,在可访问性方面需要怎么做。

换句话说,构建一个UI好看的表单往往没有构建一个可访问性好的表单重要。在构建表单的时候,特别是自定义表单的时候,为了可访问性我们应该尽可能的做到。

表单可以自动填充

允许浏览器自动填写表单,可以让访问者做更少的事情。比如说,更有可能完成表单的注册、购买等。下面两篇文章都向大家介绍了表单自动填充的重要性和如何构建一个自动填充的表单:

到目前为止,HTML 5.2为表单控件提供了autocomplete属性,该技术是目前唯一符合AA标准的技术。

使表单控件看起来像表单控件

默认情况下,浏览器对表单控件都会有相应的UI渲染,比如说<input>控件,浏览器将会把它渲染成一个带有边框的框。虽然我们可以使用CSS的样式来美化它,但要将方框保留。有很多视觉设计师会采用Google Material设计风格

然而,Google发现上图这样的设计对一些用户来说并不清晰,经常会和分隔符混淆,因此改变了设计。

@Susanna Zaraysky针对600名用户针对可用性做了一些测试,发现:

使用矩形(框)形状的封闭文本输入框比使用线条的文本输入框,可视性更好。

不要遗忘<label>标签

在构建Web表单时,每一个表单控件(比如文本输入框、复选框、单选按钮、下拉选择框等)都需要<label>标签。正如WCAG所说:

Standard HTML controls already meet this success criterion when used according to specification.

不过,有的时候开发者会采用inputplaceholder来替代<label>标签。

但是不建议这样使用。@Eric在他的《Don’t Use The Placeholder Attribute》教程中深度的分析了,为什么不建议使用plaaceholder来替代<label>标签。

当然,如果你的需求一定不需要显示表单的标签,那么也不要放弃不使用<label>标签,我们应该选择CSS样式来做处理,而且尽可能的让屏幕阅读器等辅助技术能照常识别出来,不同的只是视觉上不显示:

在《Web隐藏术》中介绍了很多种隐藏元素的方法,其中最常见的:

.sr-only { 
    position: absolute; 
    height: 1px; 
    width: 1px; 
    clip: rect(1px 1px 1px 1px); 
    clip: rect(1px,1px,1px,1px); 
    clip-path: polygon(0px 0px, 0px 0px, 0px 0px); 
    overflow: hidden !important; 
}

该方法在可访问性方面较友好,特别是对于屏幕阅读器:

除了该方式之外,还可以在表单控件上添加ARIA相关的属性,比如:

<input type="text" aria-label="Search">

相比而言,还是推荐使用CSS的相关技术来隐藏不可见的文本。@Adrian Roselli在《My Priority of Methods for Labeling a Control》一文中就针对这方面做过深入的探讨。

其他

前面也提到过了,表单是Web应用的重要组成部分之一,而且表单设计有着诸多因素的结合,而且整个链路也较长。也正因为这些因素的存在,设计一个好的表单不易,设计一个具有可访问性的表单更不易。需要每一个环节都为其做出最好的设计。

上面提到的这几个点只是其中小小的部分,而且也无法用一个小节就能把可访问性表单讲清楚。记得在《编写HTML时要考虑可访问性》和《编写CSS时要考虑可访问性》都有和大家聊过表单可访问性相关的话题,感兴趣的同学可以移步花点时间阅读。除此之外,下面这些教程都可以帮助你如何构建更具可访问性的表单。

给媒体对象提供可替换的文本

任何通过图像、视频和音频传达的信息都必须有可替换的文本内容

现代Web应用开发中,除了使用<img>之外还会使用音频和视频这些媒体对象。那么我们在使用这些媒体对象时都应该考虑提供一些可替换文本信息能同步给用户。比如<img>,大部分开发者都清楚,可以使用alt属性给图像提供可替代的文本信息。在《聊聊img元素》一文中详细的介绍了HTML的<img>使用,其中就有如何给图像提供可替代文本信息这一部分。

比如下面这个示例:

比如上图嵌入到Web时,我们就可以像下面这样给alt添加描述信息:

<!-- 不好的用法: 没有使用alt --> 
<img src="bird.png" /> 

<!-- 一般般的用法:显式设置了`alt`,但是个空值 --> 
<img src="bird.png" alt="" /> 

<!-- 好的用法:alt描述了图片的信息(公鸡),告诉用户这是只公鸡 --> 
<img src="bird.png" alt="公鸡" /> 

<!-- 更好的用法:alt描述了图片的信息(公鸡啼鸣),告诉用户这是只正在啼鸣的公鸡 --> 
<img src="bird.png" alt="公鸡啼鸣" /> 

<!-- 最好的用法:alt描述了图片的信息(红色冠公鸡啼叫),告诉用户这是只正在啼鸣的红色冠公鸡 --> 
<img src="bird.png" alt="红色冠公鸡啼鸣" />

在Web中除了会使用<img>加载图像之外,有的时候会使用一些ICON图标,Web中的图标使用方式有很多种,其中字体图标和SVG图标都是目前较为流行的。但从可访问方面来说,使用SVG图标要比使用字体图标更具优势。比如:

<button type="button">
    <svg viewBox="0 0 10 10"
        role="img"
        class="svg-icon"
        aria-labelledby="menu-icon-title"
        focusable="false">
        <title id="menu-icon-title">Menu</title>
        <path d="m1 7h8v2h-8zm0-3h8v2h-8zm0-3h8v2h-8z"/>
    </svg>
</button>

<!-- 或者 -->
<button type="button">
    <svg class="svg-icon"
        height="10"
        width="10"
        viewBox="0 0 10 10"
        aria-hidden="true"
        focusable="false">
        <path d="m1 7h8v2h-8zm0-3h8v2h-8zm0-3h8v2h-8z"/>
    </svg>
    <span class="visually-hidden">
        Menu
    </span>
</button>

有关于这方面更详细的介绍可以阅读:

视频(video)、音频(audio)和<img>使用类似,同样需要给他们提供可替代的文本信息。只不过实现的方式或者说手段不一样。

上面的截图的来自于该示例

比如video,可以通过<track>来添加可替换的文本信息:

<video width="640" height="360" poster="media/foo.jpg" controls>    
    <source src="foo.mp4" type="video/mp4" />
    <source src="foo.webm" type="video/webm" />
    <track kind="captions" label="English captions" src="media/foo.vtt" srclang="en" default />
    <div>
        <a href="foo.mp4">
            <img src="media/foo.jpg" width="640" height="360" alt="download video" />
        </a>
    </div>
</video>

有关于这方面更多的介绍还可以阅读:

添加适当的文档语言

让屏幕阅读器等辅助技术知道你的文本所使用的语言。

据WebAIM的统计得知,近30%的Web主页没有显式声明文档所使用的语言,这让屏幕阅读器用户感到困惑。去年在一次活动中做无障碍方面的时候,由于在文档(<html>)中没有显式设置lang类型,造成屏幕阅读器无法正确的识别到文档使用的语言类型。

如果你的页面文档未显式设置语言类型,用户代理将默认使用其自己的默认语言设置来渲染页面。如果页面和用户代理在同一种语言,一切都将好,然而,如何用户代理设置和页面语言类型不匹配,那对于屏幕阅读器用户来说是灾难性的。

给文档设置语言类型很简单,只需要在<html>元素中显式的设置lang属性:

<html lang="zh-CN">

W3C有一个选择语言类型的指南

如果你的页面是个中文网站,但页面内容有的地方可能包含了除主要声明的语言之外的其他语言内容,这个时候应该给包含该内容的元素添加lang属性。比如:

<p lang="en">Add proper document language</p>

使用lang属性来设置语言类型时,有些小细节也是要注意的。比如在一个HTML标签元素上,文本内容是西班牙语,而HTML属性的值又是英语,这个时候在元素标签上lang不管是显式的设置为en还是es都是一种错误的用法,比如:

<a lang="es" title="Spanish" href="qa-html-language-declarations.es">Español</a>

这个时候正确的做法是:

<a title="Spanish" href="qa-html-language-declarations.es"><span lang="es">Español</span></a>

注意,现在市场上屏幕阅读器种类繁多,不同的品牌之间的技术也有一定的差异性(有点像浏览器客户端一样)。具体的效果以实际效果为准。如果你对屏幕阅读相关的知识感兴趣的话,这里推荐你花时间阅读 @Melanie Richards的《Semantics to Screen Readers》一文。

帮助访问者了解你的内容

使用HTML地标元素来帮助屏幕阅读器等辅助技术用户更好的理解和导航你的内容

对于视力正常的用户来说,他们可以很容易地在你的网站或应用上找导航,并且导航到需要的内容所在地。但对于视力有障碍的用户的群体来说,他们访问你的网站或应用可能依赖的是像屏幕阅读器,告诉屏幕阅读器读出的信息告诉用户。值得庆幸的是,现在HTML5中提供了一些地标元素(Landmark),可以很好的帮助你对自己的内容做标记,并且屏幕阅读器等辅助技术可以根据这些标记很好的导航到所需要的内容。

HTML5中的地标元素(比如<header><main><nav><aside><footer>form<section>等)其实对标的就是ARIA中Landmark角色部分。在还没有HTML5的地标元素之前,都是通过在HTML的元素上显式添加role的值(比如applicationbannercomplementarycontentinfoformmainnavigationsearch)。HTML5地标元素和RAI的地标角色之间是有一定的对应关系:

HTML5 (Landmark) ARIA(Landmark) 描述
<header> role="banner" header<body>元素的上下文(body子元素)时才形成banner,反之,在非body元素的后代时,它就不会形成bannerrole
<main> role="main" 页面的主要内容(不包括页眉、主导航或页脚的内容),几乎所有情况下,每个页面应该只有一个<main>
<aside> role="complementary" 类似广告和非必要的内容应该放在<aside>
<footer> role="contentinfo" footer<body>元素的上下文(body子元素)时才形成contentinfo,反之,在非body元素的后代时,它就不会形成contentinfo
<nav> role="navitation" 一般情况下,使用<nav>包含<ul>的主导航,根据视觉需要,可以嵌套在别的容器中,比如<header>
<section> role="region" 当使用aria-labelledbyaria-labeltitle属性具有可访问名称时形成region
<form> role="form" 当使用aria-labelledbyaria-labeltitle属性具有可访问名称时形成from
  role="search" 搜索框,可以放置在任何块元素容器中,比如div
  role="application" 通用的div元素等

有关于Landmarks更多的内容还可以阅读:

此外,在<article>中包装离散的内容片段可以帮助苹果的WatchOS以最佳的方式显示内容。有关于这方面的更多信息,请参阅@Bruce Lawson的《The practical value of semantic HTML》一文。

正确的使用HTML

理解HTML元素的语义和默认行为,为内容使用正确的HTML元素

有关于HTML的使用相关的话题一直都是社区中探讨的话题之一,特别是有关于语义化标签元素使用相关的话题。那么在构建Web可访问性应用中,为内容使用正确的HTML元素显得更为重要。比如说,使用<main>就比<div class="main">要更好,因为它允许屏幕阅读器用户直接跳转到主要内容区域,而对那些不使用屏幕阅读器的用户则没有任何影响。

另一个例子就是我们在《它是按钮还是链接?》聊到的一样,我们不能仅仅根据UI视觉的效果来决定使用HTML标签元素。在现代Web开发中,开发都并不太关注语义化标签的使用,不管是什么时候千篇一律的<div>@BrittanyIRL分享的Accessibility Is A marathon, Not A Sprint话题中也特别的提到这方面:

如果你了解HTML的话,你会发现,在HTML中除了<div><span>两个标签之外,其他的HTML标签都具有相应的语义和默认的行为:

或许你会说,近106个元素标签,看上去都差不多,在实际使用的时候应该怎么选择呢?如果你在这方面存在凝问,可以参照下图的流程来做出正确的选择:

要想正确无语的做出选择,还是要对HTML各个标签有所了解。

其实,在《编写HTML时要考虑可访问性》一文中专门和大家聊了HTML标签元素对构建可访问的Web应用的重要性。如果你感兴趣的话,可以花点时间阅读该文。

正确的地方使用对的ARIA

只在没有适合语义的情况下使用ARIA,并且使用W3C建议的设计模式和代码

在Web开发中,总是避免不了要开发一些具有更复杂交互的组件(很多小组件对于HTML来说没有相应的标签)。在构建这些组件时,首先要考虑的是将它们简化为原生HTML交互。如果没有,那么就需要在组件中融入WAI-ARIA中的角色、状态和属性等,让你构建的组件更具可访问性。

在《WAI-ARIA初探》一文中,初步的和大家探讨了ARIA的一些基本概念和基础知识:

  • 角色:这是什么类型的“东西”?比如,它是一个button
  • 状态:它的情况如何?比如disabledchecked
  • 名称:它的名称或标签是什么?
  • 关系:它是否以某种方式与页面中的其他元素相关联?

浏览器会将这些信息映射到操作系统的可访问性 API,并将其公开给辅助技术。一旦ATs理解了含义(或目的),它可以自动读出特定的提示(或相关信息)。

使用ARIA主要可以做到:

  • 让辅助技术用户(比如屏幕阅读器)可以理解定制的小部件(Widget)
  • 以编程方式指示元素之间的关系
  • 通知用户动态更新
  • 向辅助技术隐藏不相关的可视内容
  • 未完全重新编码的不可访问内容的修复

但ARIA并不是万能的,他的使用也是会受到一定限制的,特别是ARIA的角色和属性的使用:

  • 某些角色只能作为特定复杂小部件的一部分(详细请见ARIA的角色一节)
  • 一些aria-*属性是全局的
  • 其他aria-*属性只适用于特定的角色
  • 并不是所有的角色或属性都得到一致的支持或实现

虽然ARIA在某些场景之下能增强HTML标签的语义化,但这并不代表他是万能的。特别是对于刚接触ARIA而言,你始终要记得ARIA不是魔法,也不是万能的,他仅仅只是改变了辅助技术解释内容的方式。具体的说,ARIA还有很多事情是做不到的:

  • 不能让非聚焦的元素得到焦点
  • 提供适当的键盘绑定
  • 改变浏览器的行为
  • 自动维护或更新属性
  • 变化可见的UI视觉(除CSS使用特性的选择器重构UI风格之外)

可以说,ARIA是一个庞大的体系,涉及的知识点和相关信息也非常的多,要用好ARIA并不是一件易事,但我们遵循一些使用规则会让其变得更简单些。

当你决定在Web中使用ARIA来增强Web的可访问性或者说在构建的一些组件中不得不用ARIA时,请记住下面这句话:

NO ARIA is better than bad ARIA!

如果你在构建组件时不太清楚ARIA的使用时,可以参考W3C提供的最佳实例,这个实例集包含了Web中常见的一些交互组件

比如使用div模拟的checkbox

<div role="checkbox" aria-checked="false" tabindex="0">Lettuce</div>

要是你感兴趣的话,也可以阅读《聊聊Web中的下拉选项的事情》一文中的下拉选择框,就运用最佳实践中combobox的相关规则

除了可以参考W3C规范中提供的案例之外,还可以参考Adobe团队的Spectrum指南

同样拿checkbox来举例:

<label class="spectrum-Checkbox is-invalid is-indeterminate">
    <input type="checkbox" class="spectrum-Checkbox-input" id="checkbox-2">
    <span class="spectrum-Checkbox-box">
        <svg class="spectrum-Icon spectrum-UIIcon-CheckmarkSmall spectrum-Checkbox-checkmark" focusable="false" aria-hidden="true">
            <use xlink:href="#spectrum-css-icon-CheckmarkSmall" />
        </svg>
        <svg class="spectrum-Icon spectrum-UIIcon-DashSmall spectrum-Checkbox-partialCheckmark" focusable="false" aria-hidden="true">
            <use xlink:href="#spectrum-css-icon-DashSmall" />
        </svg>
    </span>
    <span class="spectrum-Checkbox-label">Checkbox</span>
</label>

最后需要特别提出的一点是,使用非原生的HTML标签来构建带有交互的组件时,除了使用ARIA能增加Web可访问性之外,还需要使用JavaScript来做很多额外的事情,比如说使用JavaScript给组件添加一些键盘事件。毕竟你的用户群体中可能有很多用户是属性重度依赖键盘操作的那种,你不能无视或直接抛弃他们。

所以说,能用原生HTML的时候,尽可能的使用原生HTML,不管是交互、样式还是可访问性方面,他都具有独特的优势。

不应该忽略框架中的可访问性

从2019年JavaScript发展报告中我们可以知道,现在React、Vue等JavaScript成为前端开发的主流框架:

当我们使用像React、Vue等框架来开发Web应用的时候,我们不应该遗忘Web可访问方面的细节,而且这些框架也并没有限制可访问性相关的扩展,但事实上呢? 很多开发人员在开发组件的时候通常没有使用正确的HTML标签,也没有使用任何辅助技术。这样对于Web可访问性来说是糟糕的。

正如React官网有关于web可访问性也有过这样描述:

React 对于创建可访问网站有着全面的支持,而这通常是通过标准 HTML 技术实现的。

Medium.com网站上,@Emily Mears有两篇教程就是围绕着React和Vue环境下关于Web可访问性相关的讨论,感兴趣的话可以阅读:

除此之外,还有一些优势的组件库,在Web可访问方面做得也是很不错的,比如:

很多时候,第三方库可能不太能满足你的需求,如果你也正在或者尝试着使用React或Vue开发自己的组件库时,那么请考虑到Web可访问性方面的功能,如果你不清楚开发出来的组件是否具备Web可访问方面的要求,那么建议你花点时间阅读@Adrian Roselli的《Basic Custom Control Requirements》教程,这是一篇非常值得阅读的文章,文章的内容会告诉你自己定制的组件,在满足Web可访问性方面要做哪些事情。

跳转链接(Skip Links)

估计很多开发者已经将这个跳转链接给遗忘了。其实,跳转链接对于Web可访问性来说是非常有用的。一般情况,跳转链接会以一个<a>链接标签的形式放置在页面的最顶部,通过href属性与主内容区域的id绑定:

<body>
    <a href="#maincontent">Skip to main content</a>
    <!-- ... -->
    <main id="maincontent" role="main">
        <h1>Heading</h1>
        <p>This is the first paragraph</p>
        <!-- ... -->
    </main>
</body>

比如下图所示的网站,都可以看到跳转链接的身影:

跳转链接对于普通用户来说是无感知(一般会使用CSS让用户看不到),但对于屏幕阅读器或键盘用户来说是很重要的,它允许屏幕阅读器或键盘用户直接跳转到主要内容区域,它何以有效的“跳过”页面顶部的所有导航链接和菜单。对于不使用屏幕阅读器的键盘用户来说,跳转链接尤其有用,因为这些用户通常无法访问其他快速导航模式(比如地标和标题)。

添加快捷键

基本上每个Web应用都会有一些快捷键的设置,比如Chrome浏览器就提供了很多快捷键的操作:

快捷键对于重度依赖于键盘操作的用户来说是非常友好的。这样能更好的帮助键盘用户操作Web应用。但在Web网站的开发中,很少会添加快捷键。Web Almanac400万个站点做过相应的分析,并没有多少网站使用了快捷键。

在HTML中,我们有很多元素是属于可聚焦元素,往往在Web开发的时候,只会考虑给可聚焦元素添加tabindex属性,甚至这个属性都不会添加。从《使用tabindex的正确姿势》一文中,我们可以知识,tabindex可以让键盘用户知道自己来到了哪个地方。另外,tabindex还可以设置在不可聚焦元素上。

  • tabindex="-1":设置了tabindex-1的元素,该元素不会被置于页面的tab键序列中,但可以通过JavaScript的focus()获取,允许脚本设置元素的焦点。当你需要将焦点转移到通过脚本或用户操作之外更新的内容时,该设置非常方便
  • tabindex="0":可以让非常聚焦元素按自然顺序出现在tab键序列中
  • tabindex="1":不要设置tabindex="1"或任何大于0的值

在Web中,开发者可以通过aria-keyshortcutsaccesskey属性来设置快捷键,它们设置的快捷键主要用于:

  • 激活页同上的元素,比如链接<a>或按钮<button>
  • 给出页面焦点上的某个元素,比如将焦点移到页面上的某个<input>输入框,然后允许用户开始输入

400万个网站中,只有159个站点使用了aria-keyshortcutsaccesskey相对多一点,差不多占比有2.4%(其中移动端上占1.74%)。在Web应用中运用快捷键的话,估计在PC端上使用率会更高,因为PC端使用键盘操作的用户更多。

特别令人惊讶的是,15.56%的移动和13.03%的桌面站点使用快捷键,并将相同的快捷键分配给多个不同的元素。这意味着浏览器必须猜测哪个元素应该拥有这个快捷键。

页面的缩放

不知道你有没有这样的习惯,有时候访问一些网站会觉得字号太小难于阅读,就会使用cmd + (或ctrl +)这样的快捷键方式来放大页面。在移动端同样有一些手势的操作,可以用来放大和缩小页面:

这其实对于用户来说是一个很好的体验,但是在移动端开发的时候,很多开发者使用<meta>标签将该功能给禁用了:

<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,viewport-fit=cover" />

这样设置的话,如果你使用一些可访问性检测工具你会发现这样的设置通不过可访问性的检测:

如果为了让你的站点能满足用户的需求,并提供更好的体验,可以开maximum-scale的设置:

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

为了避免<meta name="viewport" >给用户造成不好的体验,iOS10开始会忽略user-scalablemin-scalemax-scale的设置。他们的改为消除了缩放的影响,使缩放成为可能。

meta标签上还有user-scalable属性的设置,它会给使用Web浏览器内置缩放功能的人带来问题。默认情况之下,user-scalable属性的值是yes,这意味着人们能够控制他们正在访问的页面的缩放设置。将其更改为no,将会阻止缩放设置。在Web可访问性方面,我们应该尽可能的避免将user-scalable设置为no,以确保用户能更好的访问你的站点。通过不引用user-scalable属性将其保留为默认。

有关于这方面的介绍还可以阅读:

保持测试

Web可访问性的开发和其他开发类似的,应该在整个开发过程中都对可访问做监测和测试。给Web网站或应用做可访问性的测试有很多工具,也有很多方法。在《如何检测和修复可访问性》和《可访问性审核的几种姿势》中对这方面做过详细的介绍。

不管使用的是浏览器的插件,还是使用命令终端或者Webpack相关的配置,这些监测和检测工具大多是基于axe-core做的。但这些检测都只能完成20%~50%,正如axe命令在检测完最后会有一段提示信息:

Please note that only 20% to 50% of all accessibility issues can automatically be detected. Manual testing is always required. For more information see: Web Accessibility Testing, Part 2: Basic Methods and Tools.

对于可访问性检测的最佳方法是通过有障碍的人士来测试。他们给出的答案将是最佳的答案。@Peter van Grieken在《Things to consider when doing usability testing with disabled people》一文针对有障碍人士进行可用性测试时写了一个有用的清单列表。另外Web.dev也提供了一份检测可访问性的评分标准。要是你感兴趣的话,还可以阅读《Building the most inaccessible site possible with a perfect Lighthouse score》一文,该文列出了难以达到Lighthouse评分常见的一些问题。

小结

构建可访问性Web网站或应用并不是一时半刻的事情,作为开发者我们应该持续去做的一件事情。只有不断的积累和优化其中的不足,才能慢慢构建出更具可访问性的Web应用。而且构建可访问性的Web应用,是每一位开发者必备的技能,而且也是应该去完成的使命。

最后,希望文章中提到的每一点,对于开发者在构建Web可访问性有所帮助。如果你在这方面有更好的建议或经验,欢迎在下面的评论中与我们一起分享。