用斧头进行自动辅助功能检查

一架无人驾驶飞机徘徊在开发人员的肩膀上,可访问性在计算机屏幕上检查网站

您花了多少时间和精力来计划上一个网站的设计,以使有特殊需要和残障的人可以访问? 我有一种预感,许多读者的答案将是“无”。 但是几乎没有人会否认,由于辨别颜色,阅读文字,使用鼠标或只是浏览复杂的网站结构等问题,有相当数量的Internet用户无法访问网站。

由于需要检查可访问性并实施解决方案,因此通常会忽略可访问性。 开发人员不仅必须熟悉基本标准,而且还要不断检查它们是否符合要求。 通过自动执行标准检查,我们可以使开发无障碍网站变得更加容易吗?

在本文中,我将向您展示如何使用斧头库和一些相关工具来自动检查和报告网站和应用程序中的潜在可访问性问题。 通过减少此类活动所需的工作量并自动化一些手动工作,我们可以为使用我们创建的事物的每个人获得更好的结果。

斧头介绍

ax是一个自动化的可访问性测试库,它已经开始将可访问性测试引入主流Web开发。 axe-core库是开源的,并且以与不同的测试框架,工具和环境一起使用的方式设计。 例如,它可以在功能测试,浏览器插件中运行,也可以直接在应用程序的开发版本中运行。 它目前支持约55条规则,以检查网站的可访问性的各个方面。

为了快速演示该库的工作方式,让我们创建一个简单的组件并对其进行测试。 我们不会创建整个页面,而只会创建一个标题。

请参阅CodePen上的SitePoint@SitePoint )进行笔斧可访问性检查

在创建标题的过程中,我们做出了一些出色的设计决策:

  1. 我们将背景设置为浅灰色,将链接设置为深灰色,因为这种颜色既优雅又时尚。
  2. 我们为搜索按钮使用了一个很酷的放大镜图标;
  3. 我们将搜索输入的标签索引设置为1,这样,当用户打开页面时,他可以按tab并立即键入搜索查询。

整洁吧? 好,让我们从可访问性的角度来看它的外观。 我们可以从CDN中添加斧头,并使用以下脚本将所有错误记录到浏览器控制台中。

axe.run(function (err, results) {
  if (results.violations.length) {
    console.warn(results.violations);
  }
});

如果运行示例并打开控制台,您将看到一个包含六个违规对象的数组,列出了我们遇到的问题。 每个对象都描述了我们违反的规则,对应归咎于HTML元素的引用,以及有关如何解决问题的帮助信息。

这是其中一个违规对象的示例,显示为JSON:

[  
   {  
      "id":"button-name",
      "impact":"critical",
      "tags":[  
         "wcag2a",
         "wcag412",
         "section508",
         "section508.22.a"
      ],
      "description":"Ensures buttons have discernible text",
      "help":"Buttons must have discernible text",
      "helpUrl":"https://dequeuniversity.com/rules/axe/2.1/button-name?application=axeAPI",
      "nodes":[  
         {  
            "any":[  
               {  
                  "id":"non-empty-if-present",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"critical",
                  "message":"Element has a value attribute and the value attribute is empty"
               },
               {  
                  "id":"non-empty-value",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"critical",
                  "message":"Element has no value attribute or the value attribute is empty"
               },
               {  
                  "id":"button-has-visible-text",
                  "data":"",
                  "relatedNodes":[  

                  ],
                  "impact":"critical",
                  "message":"Element does not have inner text that is visible to screen readers"
               },
               {  
                  "id":"aria-label",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"critical",
                  "message":"aria-label attribute does not exist or is empty"
               },
               {  
                  "id":"aria-labelledby",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"critical",
                  "message":"aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty or not visible"
               },
               {  
                  "id":"role-presentation",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"moderate",
                  "message":"Element's default semantics were not overridden with role=\"presentation\""
               },
               {  
                  "id":"role-none",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"moderate",
                  "message":"Element's default semantics were not overridden with role=\"none\""
               }
            ],
            "all":[  

            ],
            "none":[  
               {  
                  "id":"focusable-no-name",
                  "data":null,
                  "relatedNodes":[  

                  ],
                  "impact":"serious",
                  "message":"Element is in tab order and does not have accessible text"
               }
            ],
            "impact":"critical",
            "html":"<button>\n      <i class=\"fa fa-search\"></i>\n    </button>",
            "target":[  
               "body > header > div > button"
            ],
            "failureSummary":"Fix all of the following:\n  Element is in tab order and does not have accessible text\n\nFix any of the following:\n  Element has a value attribute and the value attribute is empty\n  Element has no value attribute or the value attribute is empty\n  Element does not have inner text that is visible to screen readers\n  aria-label attribute does not exist or is empty\n  aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty or not visible\n  Element's default semantics were not overridden with role=\"presentation\"\n  Element's default semantics were not overridden with role=\"none\""
         }
      ]
   },
]

如果您仅选择违规的描述,则表示:

Ensures buttons have discernible text
Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds
Ensures every HTML document has a lang attribute
Ensures <img> elements have alternate text or a role of none or presentation
Ensures every form element has a label
Ensures tabindex attribute values are not greater than 0

事实证明,我们的设计决定毕竟不是那么出色:

  1. 我们选择的两种灰色阴影没有足够的对比度,对于视力障碍的人可能很难看清
  2. 搜索按钮的放大镜图标无法为使用屏幕阅读器的用户提供按钮用途的指示
  3. 搜索输入的选项卡索引中断了使用屏幕阅读器或键盘的人员的常规导航流程,并使他们更难以访问菜单链接。

它还指出了我们没有想到的其他几件事。 总共执行约55种不同的检查,包括来自不同标准准则和最佳实践的规则。

要查看错误列表,我们必须将脚本注入页面本身。 虽然完全可行,但这不是很方便。 如果我们可以对任何页面执行这些检查而不必自己注入任何东西,那就更好了。 最好使用众所周知的测试运行程序。 我们可以使用Selenium WebDriver和Mocha做到这一点。

使用Selenium WebDriver运行斧头

要使用Selenium运行斧头,我们将使用axe-webdriverjs库。 它提供了一个可以在WebDriver之上使用的斧头API。

要设置它,让我们创建一个单独的项目,并使用npm init命令初始化一个npm项目。 随时为它要求的所有内容保留默认值。 要运行Selenium,您需要安装selenium-webdriver 。 我们将在PhantomJS中执行测试,因此我们也需要安装它。 Selenium需要Node 6.9或更高版本,因此请确保已安装它。

要安装软件包,请运行:

npm install phantomjs-prebuilt selenium-webdriver --save-dev

现在,我们需要安装axe-coreaxe-webdriverjs

npm install axe-core axe-webdriverjs --save-dev

现在已经建立了基础架构,让我们创建一个脚本来再次运行测试sitepoint.com(个人,个人)。 在项目文件夹中创建文件axe.js并添加以下内容:

const axeBuilder = require('axe-webdriverjs');
const webDriver = require('selenium-webdriver');

// create a PhantomJS WebDriver instance
const driver = new webDriver.Builder()
  .forBrowser('phantomjs')
  .build();

// run the tests and output the results in the console
driver
  .get('http://sitepoint.com')
  .then(() => {
    axeBuilder(driver)
      .analyze((results) => {
        console.log(results);
      });
  });

要执行此测试,我们可以运行node axe.js 由于我们在项目中本地安装了PhantomJS,因此无法从控制台运行它。 我们必须将其作为npm脚本运行。 为此,请打开您的package.json文件并更改默认的测试脚本条目:

"scripts": {
    "test": "node axe.js"
},

现在尝试运行npm test 。 在几秒钟内,您应该会看到斧头发现的违规列表。 如果看不到任何内容,则可能意味着SitePoint在阅读本文后已对其进行了修复。

这比我们最初的方法更方便,因为我们不需要修改正在测试的页面,并且可以使用CLI手动运行它们。 但是,这样做的缺点是我们仍然需要执行一个单独的脚本来运行测试。 如果我们可以将其与其余测试一起运行,那将更好。 让我们看看如何通过Mocha实现这一目标。

使用摩卡跑斧

Mocha是那里最受欢迎的测试跑步者之一,因此尝试使用aXe似乎是一个不错的选择。 但是,您应该能够以类似的方式将斧头与自己喜欢的测试框架集成在一起。 让我们进一步构建Selenium示例项目。

显然,我们将需要Mocha本身和一个断言库。 柴怎么样 使用以下命令安装所有组件:

npm install mocha chai --save-dev

现在,我们需要包装在Mocha测试用例中编写的Selenium代码。 使用以下代码创建一个test/axe.spec.js文件:

const assert = require('chai').assert;
const axeBuilder = require('axe-webdriverjs');
const webDriver = require('selenium-webdriver');

const driver = new webDriver.Builder()
  .forBrowser('phantomjs')
  .build();

describe('aXe test', () => {
  it('should check the main page of SitePoint', () => {
    // a Mocha test case can be treated as asynchronous 
    // by returning a promise
    return driver.get('http://sitepoint.com/')
      .then(() => {
        return new Promise((resolve) => {
          axeBuilder(driver).analyze((results) => {
            assert.equal(results.violations.length, 0);

            resolve()
          });
        });
      })
      .then(() => driver.quit())
  })
  // The test might take some 5-10 seconds to execute, 
  // so we'll disable the timeout
  .timeout(0);
});

该测试将通过检查results.violations数组的长度是否等于0来执行非常基本的断言results.violations要运行测试,请更改测试脚本以调用Mocha:

"scripts": {
  "test": "mocha"
},

此练习的逻辑下一步是在测试失败时生成更详细的错误报告。 之后,将其与您喜欢的CI环境集成以正确显示页面结果也将很有用。 我会将这两件事留给读者作为练习,然后继续使用一些有用的其他斧头配置选项。

进阶设定

默认情况下,ax将对整个页面运行所有默认检查 。 但有时更希望限制要测试的网站区域或执行的检查范围。

仅检查网站的一部分

您可以使用includeexclude方法来限制必须检查或跳过网站的哪些部分。

axeBuilder(driver)
  // check only the main element
  .include('main')
  // skip ad banners
  .exclude('.banner')
  .analyze((results) => {
    // ...
  });

如果您只想检查网站上当前正在使用的部分,或者排除无法修复或无法直接控制的部分,这可能会很有用。

选择规则

斧头中的每个规则都标有单个或多个标记,将它们分组在一起。 您也可以使用withRuleswithTags方法禁用或启用某些规​​则。

  • withRules允许您通过ID启用和配置特定规则。 例如,以下示例将仅检查颜色对比和链接名称。

    axeBuilder(driver)
    .withRules(['color-contrast', 'link-name'])
    .analyze((results) => {
      // ...
    });
    
  • withTags允许您启用标记有特定标签的规则(在这种情况下为wcag2a ):

    axeBuilder(driver)
      .withTags(['wcag2a'])
      .analyze((results) => {
        // ...
      });
    

结论

ax允许您将可访问性测试工作部分地转移到计算机上,并腾出时间来做其他事情,例如总体项目设计和结构。 尽管您仍然需要做一些工作以干净的方式将其集成到开发和CI环境中,但它仍然比手工完成要好。 当您为一个项目执行此操作时,将其与下一个项目进行集成应该很容易。

还有其他基于aXe的工具斧头Chrome插件可让您快速检查浏览器中的任何页面。 如果您使用Gulp,也会找到Gulp斧头插件 。 对于基于React的项目,有一个React StoryBook 插件 ,可让您测试React组件的可访问性。 您可能会发现其中之一更适合您的需求。

希望这将使更多的团队有动力开始考虑项目中的可访问性。 您认为:斧头看起来像是有用的工具吗? 您可以在下一个项目中尝试一下吗? 在评论中让我知道。

本文由Mallory van AchterbergDominic MyersRalph MasonJoan Yin进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!

From: https://www.sitepoint.com/automated-accessibility-checking-with-axe/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值