A11Y 101:可访问性审核的几种姿势

发布于 大漠

在《如何检测和修复可访问性》一文中和大家一起探讨了怎么让开发者在开发过程中检测和修复Web应用可访问性的问题。尽管近63%的开发者没有这方成的习惯,但如果我们想构建一个具有高可访问性的Web网站或Web应用就必须考虑可访问性相关的事项。而可访问性的一个关键方面就是审核(Accessibility Auditing)。了解应用程序是否具备可访问性,其最佳方法就是对其进行测试度量;通过这种方式,可以确定在发布到生产环境之前是否需要进行修改。

事实上大多数开发人员在开发完成的定义中都排除了“可访问性”相关的任务。比如推特上这条推文就足以说明一切:

可访问性应该是你的“完成定义”中的一部分

Web可访问审核是什么?

Technical Audit (TA) is an audit performed by an auditor, engineer or subject-matter expert evaluates deficiencies or areas of improvement in a process, system or proposal ~ Wikipedia

根据上述描述,那么可访问性审核(Accessibility Audit,缩写AA)是由开发人员、测试人员或无障碍环境专家对可访问性进行的审核,评估。并根据这些审核与评估出具一份能够指出开发工程师在开发可访问性的Web网站或Web应用中存的不足或需要改进的地方,以及提供相关的改进建议。

作为一名Web应用开发者,哪怕是你对可访问性的关注非常高,也可能需要一段时间才能掌握所有的指导原则(可访问性指导原则,即WCAG 指南),并能够从头到尾构建一个可访问性的应用,帮不会出现任何错误(事实上要做到这一点,难度还是非常的大)。换句话说,开发者掌握可访问性相关的技术和学习其他技术一样,除了了解相关的知识之外,还需要不断的练习,只有这样才能习惯A11Y的相关标准。而其中最简单的一种实践方法就是在开发过期间对代码进行审核(监测),并将所有不符合A11Y标准的错误按照修改建议进行修正

在开发过程中检查可访问性相关的问题是在生产之前修复错误的最好方法

在开发过程中要对代码进行可访问性审核,我们有一些工具、浏览器插件和库可以使用。这些都是一些强大的工具,可以自动检查可访问性问题,并在出现问题时得到通知。

为什么要审核?

大多数可访问性工具应该在已经部署的应用程序上运行,这可能会导致延迟和严重的调试问题。但这种现象也不是绝对的,因为我们有些工具和浏览器插件也可以让你在开发的过程中对可访问性进行检测和审核。呆会会和大家聊到这方面的知识。

但对于开发者而言,更喜欢的是一些自动审核的工具或库,比如:

  • 它可能是一个命令(CLI,例如pa11y
  • 它可能是开发者调试器,比如Chrome浏览器中的Lighthouse Audits
  • 它可能是一个浏览器插件,比如axe
  • 它可能是构建工程中的一个NPM包,比如eslint-plugin-jsx-a11y

这些工具或者库可以帮助开发者:

  • 节省时间,提高效率
  • 避免额外的调试
  • 掌握可访问性的相关技术

接下来我们来看看在开发一个可访问性应用时有哪些可访问审核的方式可以帮助开发者。

使用可访问性CLI工具来检测Web应用的可访问性

对于很多开发者而言,会使用可访问性CLI工具来审核自己代码的同学较少,毕竟有近63%的开发者不测试(也不检测)有关于可访问性相关的事项。部分开发者,特别是对于前端同学而言,出于习惯性,总是喜欢手动来检测。事实上,没有必要这么做,我们可以借助可访问性的CLI来帮助我们对Web应用进行自动检测。

在社区中,用来检测Web可访问性的CLI工具,最流行的应该是 pa11yaxe-cli。接下来,我们简单地来看看这两款CLI怎么实现可访问性相关的检测。

Pa11y

Pa11y是我接触的第一款有关于检测可访问性的CLI工具。使用Pa11y不需要做过多的配置,我们只需要在本地电脑中安装Pa11y即可。你只需要在命令终端执行下面命令:

❯ npm install -g pa11y

执行完上述命令之后,在命令终端执行:

❯ pa11y -h

就可以查看到Pa11y CLI所有的参数:

这样一来,可以在命令终端对任何一个Web网站或域名(包括本地的)做可访问性相关的检测。比如:

正如上图所示,会将所有碍于可访问性的原因都罗列出来,开发者可以根据每条信息进行相应的修改。

上面我们看到的是一个全局的CLI命令,如果你不太喜欢这种方式,也可以在相应的项目中配置pa11y。在相应的工程中执行下面的命令:

❯ npm install pa11y --save

然后在相应的package.json文件中的scripts项配置npm命令,比如:

// package.json

"scripts": {
    "test-a11y": "pa11y ./index.html"
}

然后在命令终端回到项目根目录之下,然后执行:

❯ npm run test-a11y

执行完上面的命令之后在命令终端会得到相应的结果,类似下图这样:

有关于pa11y更详细的介绍,还可以阅读@Godwin Ekuma的《Accessibility Testing with Pa11y and Pa11y-ci》的一文。

axe-cli

在社区中除了pa11y之外就属Deque Systems公司开发的axe-cli工具了。

Deque Systems是一家致力于可访问性研究的公司

axe-cli可以说检测可访问性领域的先驱者。它的使用有点类似于pa11y,既可以在命令终端中全局执行(可以检测任何你想检测的Web站点),也可以在对应的项目中(本地)检测可访问性。执行完相关的命令之后同样的会在命令终端中输出可访问性有问题的选项,而且也会提供相应的修改建议。

先来看全局的axe-cli全局的使用。如果想像pa11y的全局命令pa11y来检测Web可访问性的话,首先也要先安装axe-cli,可以在命令终端执行:

❯ npm install axe-cli -g

最后安装你希望使用的浏览器的Web驱动程序。Web驱动程序是用于Web浏览器的驱动程序。它允许计算上的其他程序打开浏览器并进行操作。有关于Web驱动程序的当前信息可以在selenium-webdriver项目中找到。或者可以使用Web驱动程序管理器

这个时候在命令终端上执行:

❯ axe -h

就可以查看到axe-cli相关的参数:

我们可以在命令终端上像下面这样的对任何你想要检测的Web网站进行检测:

❯ axe https://www.fedev.cn

如果被检测的应用存有可访问性问题的话将会在命令终端中将所有问题罗列出来,并提出修改建议,如下图所示:

从操作上来看,axe urlpa11y url是类似的,只不过使用的检测引擎不一样,axe-cli采用的是axe-core。在可访问性的检测上,axe-core更为流行,更接近WCAG标准。

同样的axe-cli也可以不是全局使用,在某个项目中局部使用(和pa11y-cli很相似)。在对应的根目录下执行:

❯ npm install axe-cli --save

然后同样在项目根目录下的package.json文件中的scripts选项中配置npm执行命令:

"scripts": {
    "test-a11y": "axe ./index.html"
}

回到项目根目录下执行:

❯ npm run test-a11y

当命令执行完之后,会收到有关于检测结果的信息:

虽然这些检测工具可以帮助开发者自动检测出可访问性存在的问题,但这些工具也只能检测出20%~50%的可访问性问题。有些可访问性问题还是需要手工进行检测(或测试)。所以说开发者还是需要对A11Y标准有较深的理解

时至今日,pa11y-cliaxe-cli是可访问性检测方面最为流行的两示CLI工具,他们虽然有很多相似之处,但也有各自的利弊:

CLI工具 优点 缺点 全局命令 NPM命令
pa11y-cli 设置非常简单,可以告诉你问题代码在HTML中的什么位置 离A11Y标准更远,错误信息不是很详细 pa11y <url> 可以在package.json中配置npm命令,然后当前项目中执行npm run test-pa11y(名称可以根据自己喜欢设置)
axe-cli 设置非常简单,离A11Y标准更近,错误信息很详细 不会具体告诉你问题代码在HTML中的什么位置 axe <url> 可以在package.json中配置npm命令,然后当前项目中执行npm run test-pa11y(名称可以根据自己喜欢设置)

浏览器开发者工具或插件检测可访问性

不知道你有没有发现,在执行axe <url>命令输出的结果最后会有一段免责声明:

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

为了能更多方面的检测出Web网站或Web应用可访问性存在的问题,我们在开发Web应用的过程中,可以时刻的借助浏览器开发者工具或插件来帮助我们检测可访问性相关的问题。这对于开发者而言是较熟悉的也是比较喜欢的一种方式。就Chrome浏览器而言,有很多优秀的插件可以让我们用来检测可访问性,比如下面这些插件:

就浏览器插件而言,我个人最喜欢的是 axeWave。使用浏览器插件来检测Web应用可访问性很简单,就拿axe为例吧:

Wave插件使用也类似:

浏览器除了插件之外还有自带的一些开发者工具,比如Chrome中的Lighthouse Audit就可以对可访问性做检测:

Lighthouse Audit对于可访问性的评分其权重也是基于axe的标准来进行评估的。该审核工具不会因为部分通过可访问性审核而获得分数。例如,如果页面上的一些按钮有可访问的名称,而其他按钮却没有,那么对于没有可访问名称的按钮也会直接影响页面可访问性的审核(页面在这部分最终得分也是0分)。

下面两个链接列出了Lighthouse Audit对可访问性审核的得分权重。权重更大的选项对最终的可访问性评分有更大的影响:

可能有些开发者不太喜欢Chrome浏览器。那么可以使用Firefox浏览器,Firefox浏览器也可以安装axewave这样的插件,而且他也有开发者调试器:

其他浏览器相关的检测工具这里就不一一介绍了。如果你感兴趣的话,可以自己一一尝试,要是有更好的检测工具,欢迎在下面的评论中与我们一起共享。

如何在框架中检测可访问性

时至今日,开发Web站点或Web应用不再使用以前那种古老的方式了(HTML、CSS和JavaScript),而是重度依赖一些优秀的JavaScript框架(比如React、Vue等)。对于采用框架开发的Web应用,我们可以在工程体系中使用一些优秀的NPM包来对程序的可访问进行检测评分。目前流行的NPM包主要有:

其中react-axeeslint-plugin-jsx-a11y常用于React构建的应用中,而vue-axeeslint-plugin-vue-a11y常用于Vue构建的应用中。下面我们花一点时间分别来看看React和Vue构建的应用怎么采用这些NPM包进行可访问的检测。

咱们先来看看React环境下的可访问性检测。

如何在React工程中配置可访问性代码监测

在使用React构建的项目中,我们可以使用ESLint插件:eslint-plugin-reacteslint-plugin-jsx-a11y,它们直接在你的JSX中识别和实施许多可访问性规则。将其与测试最终呈现的DOM工具(比如react-axe)结合使用,可以帮助你找到并修复站点上有关于可访问性的问题。

这两个ESLint插件使用起来并不很复杂,只需要在你的工程中像下面这样安装插件:

❯ npm i eslint-plugin-react eslint-plugin-jsx-a11y --save-dev

安装成功之后,你会看到下面这样的界面:

接下来需要对这两个插件做一点点配置相关的事情。如果你使用的是Webpack来构建工程,在项目根目录下面找到.eslintrc.js文件(该文件一般用来配置ESLint相关的选项)。分别找到extendsplugins两个配置项,然后将需要的配置分别放置到这两个项目中:

module.exports = {
    extends: [
        // ...
        "plugin:react/recommended",
        "plugin:jsx-a11y/recommended"
    ],

    plugins: [
        // ...
        "jsx-a11y"
    ],
}

重启工程之后,如果代码中有不符合可访问性规则的就会有相应的错误信息输出,如下所示:

根据错误信息,我们可以找到出错的代码位置。比如上图中告诉我们,在项目的/src/pagees/index/components/App/App.tsx17行的<img>元素缺少alt属性:

如果你的文本编辑器开启了ESLint插件功能,在编辑器也会有相应的提示,比如我自己使用的VS Code,就会有相应的提示信息,当你把鼠标悬停在相应位置,会有更详细的信息:

根据修改建议,在img标签上添加一个空的alt或者带有描述性字段的alt

<img src={String(Security)} alt="" />

保存之后你会看到代码通过了可访问性相关的检测。

有关于eslint-plugin-jsx-a11y相关的规则,可以在Github中查看

虽然eslint-plugin-jsx-a11y可以帮助你轻松地检测到JSX中的任何可访问性问题,但它不测试最终输出的HTML代码。不过,我们可以借助react-axe这个库(它是通过Deque Labs的axe-core测试工具提供的一个包)来实现这一点。

首先在你项目中执行下面这个命令来安装react-axe包:

❯ npm i react-axe --save-dev 

接下来只需要在index.js(或index.tsx)中初始化模块:

if (process.env.NODE_ENV !== 'production') {
    let axe = require('react-axe');
    axe(React, ReactDOM, 1000);
    ReactDOM.render(<App />, document.getElementById('root'));
} else {
    ReactDOM.render(<App />, document.getElementById('root'));
}

如果你的工程支持动态模块的引入(Dynamic import())的话,还可以像下面这样来初始化模块:

if (process.env.NODE_ENV !== 'production') {
    import('react-axe').then(axe => {
        axe(React, ReactDOM, 1000);
        ReactDOM.render(<App />, document.getElementById('root'));
    });
} else {
    ReactDOM.render(<App />, document.getElementById('root'));
}

这个时候,当你在开发期间运行程序时,有碍于可访问性的问题就会直接在浏览器开发者工具的控制台上输出:

注意,输出的错误信息有不同的级别提示:Minor(小错误)、Moderate(中等的)、Serious(严重的)和Critical(至关重要的)。如果输出的错误信息中看到了SeriousCritical标记时,表示对可访问性有严重的影响,需要开发者想办法来修复。

如果你希望配置一份适合自己业务或团队的react-axe配置,你还可以像下面这样使用:

if (process.env.NODE_ENV !== 'production') {
    let axe = require('react-axe');
    let config = {
        rules: [
            { id: 'heading-order', enabled: true },
            { id: 'label-title-only', enabled: true },
            { id: 'link-in-text-block', enabled: true },
            { id: 'region', enabled: true },
            { id: 'skip-link', enabled: true },
        ],
    };
    axe(React, ReactDOM, 1000, config);
    ReactDOM.render(<App />, document.getElementById('root'));
} else {
    ReactDOM.render(<App />, document.getElementById('root'));
}

有关于axe-core相关的配置可以查看其相关的API

在React中,除了react-axe之外还有另一个NPM包可以做类似的事情,即 react-a11y。使用起来也不复杂。同样需要先安装:

❯ npm install react-a11y

然后在主入口调用:

import React    from 'react';
import ReactDOM from 'react-dom';

if (process.env.NODE_ENV === 'development') {
    const a11y = require('react-a11y').default;
    a11y(React, ReactDOM, {
        rules: {
            'img-uses-alt': 'warn',
            'img-redundant-alt': [ 'warn', [ 'image', 'photo', 'foto', 'bild' ]]
            // ...
        }
    });
}

这样就会帮助我们检测应用的可访问性:

react-a11yreact-axe不同之处是,所有的规则都是关闭状态,所以在使用的时候需要先打开这些规则(通过将它们设置为warnerror)。具体规则可以在Github上查看

相比之下,就我个人而言,我更喜欢react-axe这个工具,而且axe-core被使用的地方较多

如何在Vue工程中配置可访问性代码监测

前面也提到过了,在Vue中我们可以使用eslint-plugin-vue-a11yvue-axe来监测Vue工程中的代码。这两个Lint工具和前面在React工程中使用的eslint-plugin-jsx-a11yreact-axe原理是一样的。使用方式也是一样。

我们先来看看eslint-plugin-vue-a11y的使用。在Vue工程中安装该插件:

❯ npm install eslint-plugin-vue-a11y --save-dev

vue-a11y添加到.eslintrc配置文件中:

{
    "plugins": [
        "vue-a11y"
    ]
}

或者在工程中的package.json中的extends中配置:

{
    "eslintConfig": {
        "extends": [
            "plugin:vue-a11y/base"
        ],
    },
}

来检测一下,比如在模板中添加一个不带altimg元素:

<template>
    <div id="app">
        <img  src="./assets/logo.png">
    </div>
</template>

在编编译的时候,命令终端会报错:

根据提示,给img添加alt属性(哪怕是一个空值),也可以通过检测。你感兴趣的话,可以尝试其他的检测。

你也可以根据自己的需要,在rules中配置自己想要的检测规则:

"eslintConfig": {
    "extends": [
        "plugin:vue-a11y/base"
    ],
    "rules": {
        "vue-a11y/rule-name": 2
    },
},

有关于rules的详细介绍,可以查看Github上所列的规则列表项

接下来再来看看vue-axe在Vue工程中的使用。同样的先安装vue-axe:

❯ npm install -D vue-axe

在入口文件中初始化模块:

// src/main.js
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
    render: h => h(App),
}).$mount('#app')


if (process.env.NODE_ENV !== 'production') {
    const VueAxe = require('vue-axe')
    Vue.use(VueAxe, {
        config: {
            // ...
            rules: [
                { id: 'heading-order', enabled: true },
                { id: 'label-title-only', enabled: true },
                // and more
            ]
        }
    })
}

有关于更多的规则可以点击这里查看

启用工程之后,在浏览器开发者工具中可以查看到vue-axe检测出来的结果:

有关于Vue工程中的可访问性检测和运用,@勾股老师的Vue A11y Utils非常值得大家学习

这里有一份@勾股早期分享的Topic:《Making you vue app accessible

小结

只有开发人员负责任的按照A11Y标准去编码和在编码过程中检测自己的代码,并且不断的根据检测出来的信息去修复有碍于可访问性的错误。只有这样,开发人员才能更好的掌握如何构建具有可访问性的Web应用。也只有这样,Web才能成为可访问的,包容性强的。也能让更多的人更好的访问你的Web应用。

正如文章中所介绍的,我们在编码的时候或者在构建应用的时候有很多方式可以帮助我们检测和监测有关于代码对可访问性的影响。比如CLI工具、浏览器插件,代码Lint等。不过这些工具只能帮助我们检测出20%~50%方面的问题,还有很多需要我们人工去检测。换句话说,只有我们具备更多这方面的知识,才能更好的构建可访问性的应用。

最后,希望这篇文章有助于提高自己如何借助工具来监测自己的代码,从而让自己构建的应用更具可访问性。当然,可能还有很多我不熟悉的工具或方法,如果你在这方面有经验或建议的话,欢迎在下面的评论中与我们分享。