A11Y 101:如何检测和修复可访问性

发布于 大漠

如果你最近一直在跟踪A11Y系列的话,你可能知道作为一名开发者除了完成功能需求之外,还需要花一些时间去提高Web应用的可访问性,甚至你也知道了如何通过HTMLCSS以及WAI-ARIA等方面的知识来帮助自己构建一个具有高可访问性的应用,换句话说,开发者开发一个具有可访问性的应用并没有我们想象的那么难

换句话说,每个Web网站或应用都应该通过可访问的测试并且应该有相应的检测报告,但很多团队没有足够的资源去做一个完整的,专业的测试报告(有关于应用可访问性方面)。据2019年前端工具调查报告中我们可以获知,63%的开发者没有测试可访问性

如果说开发者在开发的时候就具备一些检测可访问性的基础知识以及如何修复的话,这将能更好的帮助开发者在开发的过程就能更好的避免在应用上出现的一些常见的可访问性问题。

概述

我们都知道可访问性很重要。问题是,我们并不总是清楚我们究竟怎么做才能让自己构建的Web应用更具可访问性。虽然WCAG为我们提供了详细的文档和建议,但该规范很广泛,对于很多开发者而言要索引关键信息是有一定的难度和费时的。为了改变这一现状,在接下来的内容中,我们将针对可访问性方面来一些特殊点来处理相关的事项。换句话说,这不是一个全面的可访问性指南,但这些方法可以让我们如何避免最常见的可访问性错误。这些错误是通过WebAIM针对100万个主页的可访问性分析HTPPArchive整理的2019年Web图鉴中针对580万个页面的可访问性分析得出的。

也就是说,接下来的一些问题是最直接,最可能影响Web应用可访问性的主要问题。而且将这些主要问题根据可访问性的指导原则做一些分类。先简单的回忆一下可访问性的四个基本的指导原则

  • 可感知(Perceivable):信息和用户界面必须以用户可感知的方式呈现给用户
  • 可操作(Operable):用户界面和导航必须是可操作的
  • 可理解(Understandable):用户界面和信息的操作必须是可理解的
  • 健壮性(Robust):内容必须足够健壮,能够被各种用户代理(包括辅助技术)可靠地解释

为了满足这四项基本原则,我们可以对Web应用的可访问性做一个自动检测或者按照相应的检查清单进行检测。

可访问性的自动检测

一些Web可访问性问题(比如颜色对比度)可以通过使用一些检测工具自动检测。这些工具作为检测Web可访问性的第一步是非常好的,不过,它们最多可以检测到30%~50%的问题(可访问性方面的问题),并且有时可能是错误的。这些工具基本上有三种类型:基于Web的工具、在命令终端(CLI)中运行的工具和浏览器扩展插件和浏览器开发人员运行的工具。有时使用这些工具对于自动检测Web应用可访问性是有一定帮助的,因为每个工具都可以检测出不同的问题。

以下是我们可以用来测试Web可访问性的常用工具:

但对于开发者而言更喜欢的是使用浏览器的扩展插件或自身带有的面板。在Chrome和Firefox浏览器在这方面都具有优秀的检测插件。比如Chrome浏览器中的:

axe(Web Accessibility Testing)

axe在ChromeFirefox都有对应的插件。操作很简单:

Wave: WAVE Evaluation Tool

Wave和axe类似,在ChromeFirefox浏览器都有相应的插件。操作也类似:

另外还有很多其他的扩展插件,对于可访问性不同方面的检测有着较大的帮助,比如下图中所列的就是Chrome中的一些扩展插件:

浏览器可访问查看器

在Chrome浏览器可以使用查看器中的“Audits”选项,在Firefox中使用“无障碍环境”选项:

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

CLI:Pa11y

对于开发者而言,命令终端也是大家最常用的工具之一。如果比较频繁地在命令终端上操作的话,就可以使用Pa11y CLI来对Web做可访问性检测。

要使用Pa11y CLI,首先要在你的电脑中全局的安装pa11y-ci

➜ npm install -g pa11y-ci

安装成功之后,可以像下面这样检测你想检测的Web应用:

➜ pa11y http://192.168.31.166:3334/index

执行完上面的命令之后,pa11y会对要检测的页面进行可访问性的分析,并且输出有障碍可访问性的结果:

代码的监测

时至今日,很多开发者高度依赖一些优秀的JavaScript框架(比如,React和Vue等)来构建我们的Web应用。在整个社区也有一些优秀的Lint工具帮我们更好的监测自己编写的代码。让可访问性的检测工作更前置,简单地说,编码的时候就能让开发者更好的发现自己编写的代码是不是有障于Web应用的可访问性。在这方面比较优秀的监测工具有:

后面我们会简单的以React的环境为例,介绍如何让这些Lint工具来监测代码。如果你对这方面知识感兴趣的话,可以花点时间阅读下面这些文章:

上面提到的这些检测工具只是其中的一小部分,在社区中还有很多检测Web应用可访问性的工具或者插件:

注意,我们在前面也说到过,这些工具仅仅能帮助我们检测出部分有障碍Web应用可访问性存在的问题,而且还不一定完全准确。开发者应该根据检测出来的结果再根据可访问性相关的知识做相关的分析,以决定如何修复可访问性的问题

有碍于可访问性的六大常见现象

从WebAIM有关于可访问性的分析报告中,我们不难发现有碍于Web应用可访问性有六个最常见的现象。接下来我们来看看这几个现象以及有什么较好的方式可以修复。尽可能的让Web应用具有最好的可访问性。

检查颜色的对比度

83%的网页颜色对比度很低!

如前所述,与颜色对比度相关的问题可以通过自动化测试检测到。但并不会评估应用中哪个颜色漂亮,相反,我们感兴趣的是确保Web应用上的信息和交互元素是可感知可理解的。

根据WCAG视觉对比(WCAG Visual Contrast)规范,我们可以得知,文本与背景之间的颜色对比度应该至少是 4.5:1(可达到级别 AA)。如果文本更宽,更大和更重,那么对于视力有一定障碍的用户更便于阅读,那么颜色上的对比度就可以稍微更低一点。比如,文本字号是18pt14px粗体时,最低对比度可以下降到 3:1

颜色对比度也不是唯一与颜色有关的问题。比如说,对于一些可能患有色盲的用户,仅用颜色来传达重要信息是不够的,因为对于患有色盲的用户而言,他们的世界可能只有一种颜色。这就是为什么在给Web应用设计样式时有一些额外的约定,比如链接添加下划线,不同状态的表单元素添加一些图标等。

虽然自动检测可以帮助我们检测出颜色对比度存在的问题,但是有时候使用一些手工测试总是好的。这是因为自动测试往往在检测具有图像背景的元素的对比度和不检测元素交互状态方面存在问题。另外,自动检测也无法模拟出色盲用户访问Web应用的结果。就我个要而言,我常使用@Ada Rose Edwards的对比度检测工具,它像一个有用的剪贴板一样位于我的书签栏中,通过当前选项卡并突出显示设没有足够对比度的地方。另外@Lea Verou的Contrast Ratio工具也是不错的:

或者使用浏览器开发者工具也可以来检查和调整CSS:

这里特别向大家推荐一款Chrome浏览器的插件VisBug,可以帮你对Web应用上的任意元素的颜色对比度进行检测:

如果你希望检测特定的颜色组合,对比度检查器会给你AAAAA的评级。另外 whocanuse 还能告诉你哪种类型的视觉障碍可能会对你选择的颜色有困难:

除此之外 Accessible Brand Colors 可以帮助你检测Web应用品牌色之间的对比度; ChromeLens 可以模拟不同类型的视力障碍(包括低视力和色盲)的人如何浏览你的Web应用。

缺少图像的替代文本

高达68%的主页上的图像缺少alt文本

在Web创建中,每个<img />标签必须要有替换文本。以下是一些基本规则:

  • 如果图像是纯装饰的,它必须有空白的alt(即alt=""),这种图像一般用于CSS当中
  • 如果图像在正文中被描述,它应该有一个空白的alt,以避免重复。如果<img>被用于<figure>,那就要多加小心(具体的可以查看《How do you figure?》一文)
  • 如果图像是一个链接内容(例如网站的Logo),替代文本应该描述链接的目的地,比如alt="首页"

@botsofcode在《Alternative Text and Images》一文中详细的描述了img标签的alt的选择,如下图所示:

就可访问性而言,检查图像替代文本可能是最基本的Web可访问性特性,也是最容易实现的特性。然而,这个问题几乎没有对比性和普遍性而言:

另外,<img>alt属性提供的替代文本最初的作用不是为用户优化的,而是为SEO优化的。此外,在许多情况下,这个属性被用作在没有加载成功的图像时可以显示替代文本。然而,这并不是alt唯一(或主要)用途。ATs(比如屏幕阅读器)使用替代文本将图像内容呈现给看不到它的用户。

幸运的是,这种问题很容易通过自动测试检测到,而且HTML规范中有许多正确的alt属性示例。经验法则是根据图像渲染的上下文选择正确的替代文本

来看一个简单的示例:

在使用img引入这张图像的时候,下面这些方式都是正确的,但有好的,也有不好的(主要是指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="红色冠公鸡啼鸣" />

刚才提到过了,用于检测可访问性的工具是可以很轻易就检测出来<img>标签的alt是否有使用:

随着机器学习的出现,我们可以通过一些技术手段,自动识别图像,加上相应的alt描述文本:

详细的介绍可以参阅:

空链接和空按钮

近58%的测试主页的链接是空白的;近25%的测试页的按钮是空的

我不知道为什么会有人这么做。我假设这意味着它们是空的文本,只包含一个图像或一个文本的图像。就按钮而言,HTTPArchive Almanac说:“这种混乱的发生常常是因为缺少文本标签”。例如,一个显示左箭头的图标按钮,它表明的是“返回”,但不包含实际的文本(Web图鉴发现近75%的页面都是这样做的)。如果是这种情况,则图像需要描述按钮功能或链接目的地的替代文本。

表单的input缺少对应的label

52%的主页缺少input对应的label

结于表单中的input都应该有一个对应的可读的标签(label)。唯一例外的是type="button"input和带有hidden属性的input

label之所以如此重要,是因为ATs(比如屏幕阅读器)技术使用它们来向用户展示所关注领域的目的。没有它,用户将无法理解他们应该在对应的input中输入什么。

此外,可以看到的label对其他用户也很有帮助,因为浏览器倾向于自动填充表单。这将隐藏字段中提供的标签,并让用户怀疑表单是否被正确地自动填充。标签总是比代表相同的图标更易理解。

对于复选框(<input type="checkbox">)和单选按钮(<input type="radio">),最好提供关于整个组的用途的信息,而不是单个选项。针对于该场景,可以使用<fieldset><legend>元素会更好些:

<fieldset>
    <legend>My favorite foods</legend>

    <label>
        <input type="checkbox" name="foods" value="pizza"> Pizza
    </label>

    <label>
        <input type="checkbox" name="foods" value="burger"> Burger
    </label>

    <label>
        <input type="checkbox" name="foods" value="pasta"> Pasta
    </label>
</fieldset>

在编写HTML时,<input>除了被<label>包裹起来之外,还可以通过labelforinputid来联动,比如:

<label for="firstname">First name:</label> 
<input type="text" id="firstname" />

如果使用WAI-ARIA,还可以通过label标签的idinputaria-labelledby联动,比如:

<label id="firstname">First name:</label> 
<input type="text" aria-labelledby="firstname" />

如果不能使用label时,可以使用aria-label或者在input上使用title(在input上不太使用title属性)。

丢失的文档语言

23%主页没有为文档声明语言类型

给文档声明语言类型是很重要,因为不同的语言类型在屏幕阅读器中的发音是不同的,比如six单词在法语和英文两种类型的屏幕阅读器中的发音就非常的不同。可以在<html>元素上添加lang属性:

<html lang="en">

这样可以告诉ATs(比如屏幕阅读器)技术这个页面的主要语言是英语。

其他影响可访问性的现象

除了上述六大影响可访问性的常见现象之外,还有一些其他现象也会影响可访问性,这些也是我们开发者必检之一。

检查地标

HTML5和WAI-ARIA引入了网站地标(Landmark)的概念。它们替换了用来构建页面结构的非语义的div元素。你现在可以把你的页面划分成相应于ARIA角色的逻辑区域:

比如下面这样的一个小示例:

ATs技术使用这些区域来帮助用户轻松地在页面中导航,例如通过提供方便的按键在网站地标之间跳转。

但是据2019年Web年鉴结580万个页面的研究表明,只有26%的页面具有<main>元素,8.06%的页面错误地使用多个主要地标,这会致使用户猜测地标包含的实际内容。不过,令人高兴的是,超过50%的页面使用<nav><footer><header>。另外,在对屏幕阅读器用户的调查中,WebAIM发现26%的屏幕阅读器用户在浏览页面时经常或总是使用这些地标。

检查标题大纲

Web页面通常被称为文档。在最基本的内容层面上,它们受到报纸的启发,就像印刷文章一样,它们是用标题来划分的。实际上,在HTML中对内容进行分段的整个概念都是基于用附加标记加强标题的含义。更重要的是,研究表明,标题是屏幕阅读器用户首选的导航方法。

就我个人而言,使用标题来划分页面内容是第一原则。我从页面的主标题开始,然后是副标题:

<h1>Languages of my life</h1>

    <h2>JavaScript</h2>

    <h2>HTML</h2>

    <h2>CSS</h2>

如果某个部分需要增加一个小节,就应适当的使用其他级别的标题:

<h1>Languages of my life</h1>

    <h2>JavaScript</h2>

        <h3>History</h3>

        <h3>Current usage</h3>

    <h2>HTML</h2>

    <h2>CSS</h2>

在使用标题划分页面之后,可以为每个标题添加一个适当的分段元素:

<main>
    <h1>Languages of my life</h1>

    <article>
        <h2>JavaScript</h2>

        <section>
            <h3>History</h3>
        </section>

        <section>
            <h3>Current usage</h3>
        </section>
    </article>

    <article>
        <h2>HTML</h2>
    </article>

    <article>
        <h2>CSS</h2>
    </article>
</main>

通过这种方式,可以轻松地将整个页面划分为适当命名的部分。在使用标题划分页面时,一定要记住HTML5 Document Outline算法不起作用,因此标题级别必须与分段元素结合使用。

检查键盘导航

使用键盘浏览Web页面是Web可访问特性中最基本的一个。它由几个子特性组成。

键盘导航很重要,因为有些用户群体不能使用鼠标或触摸板。键盘导航适用于手臂或手有残疾的人,有运动缺陷的人,或者手臂受伤和受环境影响不能使用手的人(比如正抱着孩子在浏览Web),以及高度依赖于键盘操作的用户。

跳到主内容(Skip链接)

提供帮助用户导航、查找内容和确定位置的方法

页面结构通常以链接到主内容区域的主标题开始(通常隐藏在下拉菜单中,或是一个独立的锚点链接,被称为Skip Link)。

为用户提供跳转到页面主要内容的链接。网站的最开始应该应该有一个这样的链接,这样方便用户绕过其他的内容(比如菜单)就可以直接跳到主内容区域。这对于具有大型、多层导航菜单的页面尤其重要。当失去焦点时,链接本身是不可见的。比如:

<head>
    <style>
        #skip_to {
            position: fixed;
            left: 0;
            top: 0;
            opacity: 0;
        }
        #skip_to:focus {
            opacity: 1;
        }
    </style>
</head>
<body>
    <a href="#main_content" id="skip_to">Skip to Main Content</a>

    <nav> <!-- Navigations links here --> </nav>

    <div id="main_content">
        <!-- Main content here -->
    </div>
</body>

同一个页面应该可以被多个页面上的链接访问。例如,一个站点可以有:

  • 在一个页面上有完整的站点地图
  • 搜索可以访问所有内容
  • 链接到所有页面的导航

提供有关当前页面与网站其他部分的关系的信息也是很有用的。我们可以像下面这样来实现:

  • 面包屑
  • 站点地图
  • 在导航中空出显示当前位置
  • 使用<link rel="index | next | prev | contents">来指定当前页面与其他页面的关系

可访问交互元素

每个链接、按钮或其他交互元素都应该可以通过键盘访问。这意味着每个交互元素都应该是可聚集的。它可以通过使用<a><button>标记来实现。事实上,页面上如果具有交互行为,应该尽可能的使用带有可聚焦的元素。

可聚焦元素的选择需要根据语义和相关信息来选择,这种选择也是非常的痛苦,较好的一个严则就是根据HTML语义来进行选择。比如<a><button>的选择:

就该示例而言,我们就可以按这样的经验法则来进行选择:

如果它触发了导航,那它就是一个链接;如果它在页面上触发一个动作,那它就是一个按钮

正确的聚焦顺序

默认情况之下,聚焦元素的聚焦顺序是按元素在DOM中出的顺序来排序的。这意味着元素的视觉顺序应该与DOM顺序一致。否则,用户就会感到困惑,并失去当前的焦点位置。

但在复杂的布局中要保持焦点顺序正确是较为困难的。

当前焦点位置的指示器是可见的

当使用Tab键导航时,当前的焦点位置由适当的:focus样式表示。检查聚焦元素是否有可见的聚焦指示器非常重要。它可以是一个outline样式,也可以是一个下划线、一个指向箭头,甚至还可以是一些微动效。

基于时间的媒体的替代方案

为基于时间的媒体提供替代方案

基于时间的媒体(比如音频和视频)对于有听力或视觉障碍的人来说尤其困难。除了提供纯文本替代之外,提供基于时间的替代媒体版本也很有帮助。例如:

  • 为视频添加手语
  • 替代音频的视频文件
  • 视频文件和手语替代音频文件

给音频和视频元素提供替代文时,可以使用track元素为这些媒体元素指定定时的文本跟踪。

<!-- Format of the track element -->
<track kind="subtitles | captions | descriptions" src="path/to/file.vtt" srclang="" label="">

<!-- Example caption for an audio file -->
<audio controls>
    <source src="myaudio.ogg" type="audio/ogg">
    <track src="caption_en.vtt" kind="captions" srclang="en" label="English">
</audio>

<!-- Example descriptions of a video file in English and German -->
<video poster="myvideo.png" controls>
    <source src="myvideo.mp4" srclang="en" type="video/mp4">
    <track src="description_en.vtt" kind="descriptions" srclang="en" label="English">
    <track src="description_de.vtt" kind="descriptions" srclang="de" label="German">
</video>

避免触发癫痫发作的任何操作

不要以已知会导致癫痫发作的方式设计内容

很多动效会导致癫痫发作,比如每秒钟闪灯次数不应该超过三次。或者,闪光应该低于一般闪光和红色闪光阈值。如果您不确定,可以使用光敏癫痫分析工具Flash测试来测试你的站点或应用。

一般患有癫痫病的用户都有可能会通过下面的方式开启减少运动(Reduce Motion):

为此,为了避免这种现象出现,媒体特性中提供了prefers-reduced-motion条件来做判断:

@media (prefers-reduced-motion: reduce) { 
    * { animation: none; } 
}

小结

当然,该文所列的检查项不能代替由专业的Web可访问性专家测试的结果。它也不能用真正的用户来代替更广泛的测试。但是,它可以帮助你扩展有关包容性设计和Web可访问性的知识,并可以帮助你解决影响可访问性的一些常见的问题。这些虽然都是很小的事情,但要记住,这些小小的改变也很重要。值得记住的是,遵守WCAG规范不仅是正确的,而且还可以增加你的网站流量,潜在的受众和商业机会。

如果你喜欢这篇文章,我会感到很高兴,说明你也开始在关注可访问性相关的事情,也在为更多的人可以更好的访问Web做出自己的努力。如果你在这方面有相关的经验或建议,欢迎在下面的评论中与我们一起共享。