构建无障碍功能更出色的 Angular 应用

b23a30a52c1169e4.png

无障碍功能是 Web 开发的重要环节,可确保用户能够感知、了解、浏览应用以及与应用互动。在美国,每 4 名成人中就有 1 人身患会影响其主要生活行动的残疾。在全世界范围内,约有 15% 人口(超过 10 亿人)患有某种形式的残疾,其中约有 2 - 4% 的人面临实质性的困难。

影响人们使用网络的常见情况包括失明或弱视、失聪或听力受损、运动技能受限、认知障碍和色盲,而且这些情况只是其中的一部分。

在本课程中,a11y 是无障碍功能的简写形式。请注意,a 后跟 11 个字符再加 y

如需深入了解设计无障碍应用的问题及技巧,请参阅无障碍功能

要构建的内容

  • 利用最佳做法和内置技术来解决 Dumpling Shop Angular 演示应用中的常见网络无障碍功能问题
  • 符合所有无障碍功能指南、WCAG 2.0 和 ARIA 1.2,并通过 Axe 和 Lighthouse 无障碍功能审核。

818cc91d17fae486.png 510ca511c265da81.png

学习内容

您将了解 Angular 应用中会影响用户的八种常见无障碍功能问题、如何找出这些问题以及如何解决这些问题。更具体地说,您可以:

  • 使用 Google Chrome 开发者工具、Lighthouse 和 Axe 审核您应用的无障碍功能
  • 利用独特页面标题解决单页应用 (SPA) 问题
  • 为弱视用户解决低色彩对比度问题
  • 使用语义 HTML 来确保屏幕阅读器在网页中正确地导航
  • 使用 Angular Material 和解除嵌套控件来确保屏幕阅读器可以访问所有控件
  • 为屏幕阅读器添加 ARIA 支持
  • 导入并使用 Angular CDK a11y 软件包
  • 使用 FocusTrap 进行自定义组件屏幕阅读器导航
  • 使用 CDK LiveAnnounce 播报通知
  • 检测使用高对比度模式的用户,并实现高对比度主题

所需的条件

获取代码

您可以在 GitHub 代码库中找到所需的有关此项目的所有内容。首先,请克隆代码并在您常用的开发环境中打开。

克隆代码库并提供应用

建议使用 VSCode 或本地 IDE 来处理此 Codelab。

  1. 打开新的浏览器标签页,然后转到 https://github.com/googlecodelabs/angular-accessibility
  2. 创建代码库分支并克隆代码库,然后通过 cd angular-accessibility/ 命令进入到代码库中。
  3. 查看启动方式代码分支 git checkout get-started
  4. 在 VSCode 或您的首选 IDE 中打开代码。
  5. 运行 npm install 以安装运行服务器所需的依赖项。
  6. 运行 ng serve 以运行服务器。
  7. 打开一个浏览器标签页以访问 http://localhost:4200

从何处入手?

首先,针对此 Codelab 设计一个基本的餐厅应用。代码已简化为显示此 Codelab 中的概念,而且几乎没有功能。

93a2d45cdd58d830.png

浏览演示

首先,请浏览应用的三个功能:

  1. 使用导航栏查看 Our ShopOur StoryFind Us 路线,并了解这家饺子公司的详细信息。
  2. 更改主题以切换浅色和深色模式。
  3. 自定义订单的饺子馅料、数量和颜色。
  4. 选择 Purchase 以在控制台中记录您的自定义订单。

使用 Angular 解决常见的网络无障碍功能问题

在此 Codelab 中,您将关注此应用的现有功能的无障碍服务。您需要先找出应用中的 a11y 问题,然后实施解决方案来将 🛑? 变为 ✅。

如何知道要解决哪些问题?

首先,请混合使用手动测试和自动测试,以便确认无障碍功能存在的问题。

在当前的网络状态下,必须手动测试无障碍功能。

您可以借助工具来找出无障碍功能的问题,但没有任何工具能证明应用完全符合无障碍要求。手动测试可确保您对涉及逻辑内容顺序和功能对等的一系列 a11y 概念进行测试。

手动测试

要手动测试本课程中的无障碍功能,请开启计算机的内置屏幕阅读器,并使用键盘导航浏览您的应用。如需了解详情,请参阅语义和屏幕阅读器

开启屏幕阅读器并浏览屏幕即可进行练习。

您可以使用 MacOS 内置的 VoiceOver。依次点击 System Preferences > Accessibility > VoiceOver > Enable VoiceOver to turn it on。要切换 VoiceOver 的开关状态,请在按住 Command 键的同时快速按 TouchID 三次。

在本课程中,您主要手动测试问题,并使用自动化工具帮助检查特定的可自动化功能。

自动测试

您还可以使用一些开发工具来自动运行和审核您的应用。这些工具可让您检查图片中是否存在替代文本或文本颜色的对比度等。您可以将这些工具视为 Linter;它们可以识别是否存在替代文本,但您必须手动检查内容是否符合逻辑并提供了价值。

Lighthouse 和 Chrome 开发者工具

  1. 打开 Chrome 开发者工具。
  2. 选择 Lighthouse 标签页,然后选中无障碍功能复选框。
  3. 点击生成报告以运行 a11y Lighthouse 审核。

3935811012517f4e.png

Axe

  1. 安装 axe DevTools 扩展程序。您可能需要重新启动浏览器才能看到该扩展程序。
  2. 打开 Chrome 开发者工具。
  3. 选择 axe DevTools 标签页,然后选择 扫描我的所有页面 (Scan all of my page) 以运行 axe DevTools 扫描。

7033f0ef4c1c3210.png

执行 lint 请求

您可以使用 Angular ESLint 规则来对可自动化的 a11y 属性对应的代码执行 lint 请求。

.eslintrc.json 中,添加以下要应用于无障碍功能的代码:

"@angular-eslint/template/accessibility-alt-text": 2,
"@angular-eslint/template/accessibility-elements-content": 2,
"@angular-eslint/template/accessibility-label-for": 2,
"@angular-eslint/template/no-positive-tabindex": 2,
"@angular-eslint/template/accessibility-table-scope": 2,
"@angular-eslint/template/accessibility-valid-aria": 2,
"@angular-eslint/template/click-events-have-key-events": 2,
"@angular-eslint/template/mouse-events-have-key-events": 2,
"@angular-eslint/template/no-autofocus": 2,
"@angular-eslint/template/no-distracting-elements": 2

如需了解详情,请参阅 GitHub 中的最新 ESLint 规则。

您的起点

使用新的测试方法,您可以通过 Lighthouse 和 axe 审核以及手动 VoiceOver 找出应用中的以下问题:

1356f16f5505c9c9.png

无障碍功能审核:

  • 🛑 所有网页的标题都相同
  • 🛑 元素的色彩对比度必须足够高
  • 🛑 HTML 应具有逻辑顺序、名称和角色
  • 🛑 屏幕阅读器无法选中嵌套复选框
  • 🛑 屏幕阅读器无法读出滑块值
  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

提供简洁独特的网页标题可以帮助使用 a11y 服务的用户快速了解网页的内容和用途。网页标题对于有视觉障碍的用户而言至关重要,因为它们是屏幕读取软件播报的第一个页面元素。

Angular 是单页应用,因此大部分转换(例如移到新页面)不涉及重新加载页面。也就是说,每个网页都具有相同的标题,而且对于理解网页的内容或用途没有任何价值。

完成本部分后,您的应用将通过以下审核:

  • 🛑 所有网页的标题都相同

您可以在注释下方找到其中每个步骤:TODO: #4. Define unique page titles.

找出问题

要找出此问题,请开启屏幕阅读器,然后在 Our ShopOur StoryFind Us 标签页之间切换,以查看网页标题:

  1. 开启 VoiceOver。
  2. 使用标签页导航功能在网页之间切换。
  3. 验证 Angular 中的网页标题是否始终为 a11y。

这算是一个问题,因为网页标题必须各不相同,这样用户不必浏览各个网页即可快速了解网页的相关内容。

cb92438126bb2be8.png

添加有意义的网页标题

如果某个网页或视图发生了更改,您需要妥善管理网页标题。要解决这个问题,您可以使用 Angular 的 Title 服务为每个网页定义独特的标题。

  1. 为三个已定义路线中的每个路线添加各不相同的标题:

src/app/app-routing.module.ts

const routes: Routes = [
  { path: 'shop', component: ShopComponent, data: {title: 'Our Shop – a11y in Angular'} },
  { path: 'about', component: AboutComponent, data: {title: 'Our Story - a11y in Angular'} },
  { path: 'locate', component: LocationComponent, data: {title: 'Find Us - a11y in Angular'} },
  { path: '',   redirectTo: '/shop', pathMatch: 'full' },
  { path: '**', component: ShopComponent },
];
  1. 使用 Title 服务根据路线数据设置网页标题:

src/app/app.component.ts

import { Title } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map } from 'rxjs/operators';

export class AppComponent implements OnInit {
  title = 'a11y in Angular';

  constructor(private titleService: Title,
              private router: Router,
              private activatedRoute: ActivatedRoute) {}

  ngOnInit(): void {
    const appTitle = this.titleService.getTitle();
    this.router
      .events.pipe(
        filter(event => event instanceof NavigationEnd),
        map(() => {
          const child = this.activatedRoute.firstChild;
          if (child?.snapshot.data.title) {
            return child?.snapshot.data.title;
          }
          return appTitle;
        })
      ).subscribe((title: string) => {
        this.titleService.setTitle(title);
      });
  }
}

验证更改

开启屏幕阅读器,验证您的更改。现在,这些网页的标题应该各不相同了。

5a85fdb689464137.png

无障碍功能审核:

  • 所有网页的标题各不相同
  • 🛑 元素的色彩对比度必须足够高
  • 🛑 HTML 应具有逻辑顺序、名称和角色
  • 🛑 屏幕阅读器无法选中嵌套的水果复选框
  • 🛑 屏幕阅读器无法读出滑块值
  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

您的设计可能看起来很酷,但如果患有色盲症等有视觉障碍的用户无法阅读您的内容,那也酷不起来了。《网络内容无障碍指南》(WCAG 2.0) 定义了一系列色彩对比度,帮助确保用户可以无障碍地阅读内容。在 Angular 和 Web 中,您可以定义调色板,确保您的组件符合这些标准,并且弱视和有色盲症的用户能够看到这些组件。

完成本部分后,您的应用将通过以下审核:

  • 🛑 元素的色彩对比度必须足够高

您可以在注释下方找到其中每个步骤:TODO: #5. Ensure adequate color contrast.

使用 Chrome 开发者工具找出对比度较低的问题

要找出此类问题,请使用 Chrome 开发者工具检查应用中的元素。

  1. 使用检查工具可以查看菜单图标按钮。您可以看到对比度为 1.85,远低于 WCAG 要求

b2e27bca38a1649c.png

  1. 请在 Lighthouse 或 axe 的扫描中运行无障碍功能审核,以查看以下对比度问题。

c1cbc422fcdc89b.png

更改 Material 主题颜色

组件配色方案是在自定义 Material 主题中定义的。您可以更新主题值,使其符合色彩对比度指南的要求。

更新您的 Material 主题以使用较深的文本颜色,从而提高图标的对比度:

src/styles.scss

$light-primary: mat.define-palette(mat.$pink-palette, $default: A100, $lighter: 100, $text: 900);

您还可以使用 Chrome 开发者工具的内置无障碍工具查找符合标准的颜色,或更新 Sass 中的各个颜色值。

验证更改

再次检查这些元素并验证您的更改。各网页现在的标题应该各不相同了。

a990337d9f3127fd.png

无障碍功能审核

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 🛑 HTML 应具有逻辑顺序、名称和角色
  • 🛑 屏幕阅读器无法选中嵌套的水果复选框
  • 🛑 屏幕阅读器无法读出滑块值
  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

原生 HTML 元素可捕获多种对无障碍功能很重要的标准交互模式。虽然段落可设置为 span 样式,且 div 可以设置为按钮样式,但语义 HTML 元素可确保屏幕阅读器和键盘导航能够理解 HTML 的交互和控件。

在编写 Angular 组件时,您应尽可能直接重用这些原生元素,而不是重新实现需要良好支持的行为。这可确保网页的内容结构良好、内容流自然,并且标签页具有逻辑顺序,能够帮助用户有效利用键盘来浏览网站。

完成本部分后,您的应用将通过以下审核:

  • 🛑 HTML 应具有逻辑顺序、名称和角色

您可以在注释下方找到其中每个步骤:TODO: #6. Use Semantic HTML.

找出问题

  1. 开启 VoiceOver。
  2. 使用标签页导航功能找到 Our Story 标签页。
  3. 请注意标签页的顺序不是连续的。
  4. 点击 Purchase
  5. 请注意,该按钮未被识别为按钮。

69b5875f4d51d836.png

将 <div> 更改为 <button>

将自定义 <div> 替换为 Material 按钮:

src/app/shop/shop.component.html

<button mat-flat-button
  color="primary"
  class="purchase-button"
  (click)="fauxPurchase()">
  Purchase
</button>

依序使用标题元素

重新排列文本顺序以使用语义 HTML 并应用采用 Angular Material 排版的样式:

src/app/about/about.component.html

<h2>Who are we?</h2>
<p class="mat-subheading-2">Have you ever thought, "wow, I love dumplings"?</p>
<p class="right mat-subheading-1">Who hasn't.</p>
<p class="center mat-subheading-1">We took it one step further and created Dumpling Dumpling,</p>
<p class="center mat-subheading-1">double the dumpling, double the fun.</p>
<div class="spacer"></div>
<h2>How are we different?</h2>
<p class="mat-subheading-2">Handmade in San Francisco, California, we craft fully customizable dumplings. Glitter? Rainbows? Vegan? We do it all.</p>
<p class="right mat-subheading-2">This shop is concept only.</p>

验证更改

开启屏幕阅读器,验证您的更改。VoiceOver 现在能够识别按钮,并按逻辑顺序读出文本内容了。

无障碍功能审核:

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 语义 HTML 可确保逻辑交互
  • 🛑 屏幕阅读器无法选中嵌套的大小复选框
  • 🛑 屏幕阅读器无法读出滑块值
  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

对于无障碍服务而言,嵌套控件是一个复杂的交互模式。想一下菜单子项或嵌套的复选框。如何向用户指明您可以选择选项下的一组内容或导航到父菜单项?

在 Angular 中,您应尽可能地简化控件,从而简化菜单和控件以创建可导航的组件。在此示例中,您将使用 Angular Material 的列表框来构建此交互模式的一个示例。

完成本部分后,您的应用将通过以下审核:

  • 🛑 屏幕阅读器无法选中嵌套的大小复选框

您可以在注释下方找到其中每个步骤:TODO: #7. Create selectable controls with Angular Material.

找出问题

为了找出此问题,我们将会开启屏幕阅读器并尝试选择嵌套复选框。

  1. 开启 VoiceOver。
  2. 选择不同的馅料口味。
  3. 请注意,当通过 VoiceOver 读出文本内容时,如果选中父复选框,并不会指出相应子项。这样,在取消选中 Bok Choy 复选框后,您如何知道 Vegan 复选框也会被取消选中?

885a9bd0dbbd842a.png

Angular Material 中的 a11y

将语义复选框替换为 Angular Material 复选框(其中包含此交互模式的内置信息)。请务必注意,将组件替换为 Material 并不能保证实现无障碍功能。与任何其他组件一样,您需要手动测试,因为有很多种方法实现方式都会导致 Material 不具备无障碍功能。

将复选框替换为 Material 复选框

  1. 首先,添加新的馅料列表,并添加一个存储您选择的馅料口味的变量:

src/app/shop/shop.component.ts

@Component(...)
export class ShopComponent implements OnInit {
  fillings: string[] = ['Bok Choy & Chili Crunch', 'Tofu & Mushroom', 'Chicken & Ginger', 'Impossible Meat & Spinach'];
  selectedFillings: string[] = [];

  fauxPurchase(): void {
    let flavor = '';
    this.selectedFillings.forEach(filling => {
      flavor = flavor + " " + filling
    })
  }
}
  1. 添加一个 <mat-selection-list> 以替换 HTML 复选框的这一杂乱的分组:

src/app/shop/shop.component.html

<mat-selection-list [(ngModel)]="selectedFillings"
  aria-label="Dumpling fillings">
  <mat-list-option *ngFor="let flavor of fillings"
    [value]="flavor"
    color="primary">
    {{ flavor }}
  </mat-list-option>
</mat-selection-list>

您的 TODO 注释还会显示您可以在何处移除 src/app/shop/shop.component.scss 中未使用的 Sass 以清理样式。

验证更改

开启屏幕阅读器,验证您的更改。复选框现在可以被选中,并可使用屏幕阅读器以更加直观的方式进行导航了。

e9d473e1e7949442.png

无障碍功能审核:

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 语义 HTML 可确保逻辑交互
  • 屏幕阅读器可使用所有控件
  • 🛑 屏幕阅读器无法读出滑块值
  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

您修改了 Angular 应用的语义 HTML 和 Material 组件,但某些组件需要特定的属性才能完全通过屏幕阅读器浏览。

无障碍网络倡议的无障碍丰富互联网应用规范(WAI-ARIA 或 ARIA)可帮助解决无法通过原生 HTML 管理的问题。您可以指定属性,以修改元素转换为无障碍功能树的方式。

完成本部分后,您的应用将通过以下审核:

  • 🛑 屏幕阅读器无法读出滑块值

您可以在注释下方找到其中每个步骤:TODO: #8. Provide control labels with ARIA.

找出问题

要找出此问题,请开启屏幕阅读器并移动滑块:

  1. 开启 VoiceOver。
  2. 转到数量滑块并更改值。
  3. 请注意,值标签缺失。

2d7dd751d8f835e6.png

使用 ARIA 属性

<mat-slider> 使用 aria-label 以进行标签控制:

src/app/shop/shop.component.html

<mat-slider
  aria-label="Dumpling order quantity slider"
  id="quantity"
  name="quantity"
  color="primary"
  class="quantity-slider"
  [max]="13"
  [min]="1"
  [step]="1"
  [tickInterval]="1"
  thumbLabel
  [(ngModel)]="quantity">
</mat-slider>

验证更改

开启屏幕阅读器,验证您的更改。现在您可以移动滑块了!

b21560426b30352c.png

无障碍功能审核:

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 语义 HTML 可确保逻辑交互
  • 屏幕阅读器可使用所有控件
  • 滑块使用 ARIA 属性提供标签
  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

到目前为止,您已借助内置的 Angular 工具解决了常见的 a11y 问题。现在,让我们了解一下 CDK 的 a11y 模块,以及它如何帮助解决 Angular 特有的更复杂的问题。

完成本部分后,您将使用 Angular a11y 模块工具继续完成本课程。

您可以在注释的下方找到以下步骤:TODO: #9. Add the power of @angular/cdk/a11y.

导入模块

将模块添加到您的应用中:

src/app/app.module.ts

import { A11yModule } from '@angular/cdk/a11y';

@NgModule({
  declarations: [...],
  imports: [
    A11yModule
  ],
  providers: [...],
  bootstrap: [...]
})

'@angular/cdk/a11y'作用是什么?

a11y 模块提供了许多用于改进无障碍功能的工具,对组件创建者非常有用。

在以下部分中,您将添加三项常用服务:FocusTrap、LiveAnnounce 和 HighContrast。

如需详细了解 @angular/cdk/a11y 提供的所有其他服务,请参阅无障碍功能

当对话框或模态窗口打开时,用户仅在其内部进行互动。如果允许焦点移出对话框,会导致混合上下文,并造成用户不知道他们在页面上的什么位置的情况。

在 Angular 中,cdkTrapFocus 指令用于限制元素中的焦点 tab-,旨在为模态对话框等必须限制焦点的组件提供无障碍功能体验。

完成本部分后,您的应用将通过以下审核:

  • 🛑 颜色选择器中的屏幕阅读器焦点退出对话框

您可以在注释的下方找到以下步骤:TODO: #10. Control focus with FocusTrap.

找出问题

要找出此问题,请开启屏幕阅读器并打开颜色选择器对话框。

  1. 开启 VoiceOver。
  2. 使用标签页导航功能更改颜色。
  3. 在颜色选择器中查看视觉焦点顺序和焦点陷阱。

2cad39ca0450a28e.png

添加 FocusTrap

cdkFocusTrap 可用于限制和控制自定义组件中的焦点顺序。通过使用 mat-dialog-content 将焦点限制在一个对话框中足以解决大多数问题。添加属性 cdkFocusInitial,定义颜色选择器对话框中用于选择的饺子皮颜色 <mat-selection-list> 的初始焦点区域。

src/app/shop/color-picker/color-picker-dialog/color-picker-dialog.component.html

<mat-selection-list #colors aria-label="Dumpling wrapper color" multiple="false" cdkFocusInitial>
  ...
</mat-selection-list>

验证更改

开启屏幕阅读器,验证您的更改。现在,焦点最初设置在对话框中的 Change Color 处。

无障碍功能审核:

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 语义 HTML 可确保逻辑交互
  • 屏幕阅读器可使用所有控件
  • 滑块使用 ARIA 属性提供标签
  • 颜色选择器具有正确的焦点陷阱
  • 🛑 系统无法播报更改、错误和通知
  • 🛑 未启用高对比度模式

当网页上的内容发生变化时,屏幕阅读器需要收到通知。假设您尝试提交表单或完成购买,却不知道弹出了阻止表单提交的错误,这是多么糟糕!

LiveAnnoler 用于向使用 aria-live 区域的屏幕阅读器用户播报消息,以确保屏幕阅读器会收到有关实时页面更改的通知和其他通知。如需详细了解 aria-live 区域,请参阅 W3C 的 WAI-ARIA。在 Angular 中,将 LiveAnmitter 作为服务调用是比使用 aria-live 属性更具可测试性的解决方案。

完成本部分后,您的应用将通过以下审核:

  • 🛑 系统无法播报更改、错误和通知

您可以在注释的下方找到以下步骤:TODO: #11. Announce changes with LiveAnnouncer.

找出问题

要找出此问题,请开启屏幕阅读器,然后选择 Purchase,但不填写表单字段:

  1. 开启 VoiceOver。
  2. 使用标签页导航功能更改颜色并进行虚拟的购买交易。
  3. 请注意,当退出对话框并且购买交易未被读出时,系统不会指示所选的颜色。

8ec0de4079feaae7.png

将 LiveAnnouncer 添加到您的代码中

添加 LiveAnnoler,并以字符串形式播报颜色选择和虚拟的购买交易。在实际的实现过程中,当您转到第三方付款系统或遇到表单错误时,系统可能会实时播报。

  1. 在选择颜色时添加公告:

src/app/shop/color-picker/color-picker-dialog/color-picker-dialog.component.ts

import { LiveAnnouncer } from '@angular/cdk/a11y';

@Component(...)
export class ColorPickerDialogComponent implements OnInit {
  constructor(
    public dialogRef: MatDialogRef<ColorPickerDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: ColorDialogData,
    private liveAnnouncer: LiveAnnouncer) { }

  public changeColor(color: string): void {
    this.liveAnnouncer.announce(`Select color: ${color}`);
    this.dialogRef.close();
  }
}
  1. 在发生虚拟购买行为时添加公告:

src/app/shop/shop.component.ts

import { LiveAnnouncer } from '@angular/cdk/a11y';

@Component(...)
export class ShopComponent implements OnInit {

  constructor(private liveAnnouncer: LiveAnnouncer) { }

  fauxPurchase(): void {
    let flavor = '...';
    const fakePurchase = `Purchase ${this.quantity} ${flavor}dumplings in the color ${this.color}!`;

    this.liveAnnouncer.announce(fakePurchase);
  }
}

验证更改

开启屏幕阅读器,验证您的更改。您现在会收到有关错误的通知!

无障碍功能审核:

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 语义 HTML 可确保逻辑交互
  • 屏幕阅读器可使用所有控件
  • 滑块使用 ARIA 属性提供标签
  • 颜色选择器具有正确的焦点陷阱
  • 播报更改、错误和通知
  • 🛑 未启用高对比度模式

Microsoft Windows 支持一个名为“高对比度模式”的无障碍功能。此模式会改变所有应用(包括 Web 应用)的外观,以大幅提升对比度。在 Angular 中,您需要尊重用户在应用中的偏好设置。

HighContrastModeDetector 可用于确定浏览器当前是否用在处于高对比度模式的环境中。

Internet Explorer、Microsoft Edge 和 Firefox 支持此模式。Google Chrome 不支持 Windows 高对比度模式。此服务无法检测 Chrome 高对比度浏览器扩展程序添加的高对比度模式。

完成本部分后,您的应用将通过以下审核:

  • 🛑 未启用高对比度模式

您可以在注释的下方找到以下步骤:TODO: #12. Enable HighContrast mode.

找出问题

要找出此问题,请在 Internet Explorer、Microsoft Edge 或 Firefox 中打开您的应用,开启高对比度模式,并观察是否有变化:

  1. 在 Internet Explorer、Microsoft Edge 或 Firefox 中打开应用。
  2. 开启高对比度模式。
  3. 请注意,应用没有变化。

添加对高对比度模式的支持

styles.scss 中,使用 @angular/cdk/a11y 中提供的 cdk-high-contrast mixin,在高对比度模式下为按钮添加外框:

src/app/shop/shop.component.scss

@import '~@angular/cdk/a11y';

.purchase-button {
    border-radius: 5px;
    background-color: mat.get-color-from-palette(mat.$pink-palette, A100);

    @include cdk-high-contrast {
      outline: solid 1px;
      background-color: mat.get-color-from-palette(mat.$pink-palette, 50);
    }
}

:host-context(.dark-theme) {
  .purchase-button {
    background-color: mat.get-color-from-palette(mat.$light-green-palette, A100);

    @include cdk-high-contrast {
      outline: solid 1px;
      background-color: mat.get-color-from-palette(mat.$light-green-palette, 50);
    }
  }
}

验证更改

刷新您的应用并验证您所做的更改。您在高对比度模式下为按钮添加了外框。

83c10ae8bd841e2e.png cb49574f76cdb85c.png

无障碍功能审核:

  • 所有网页的标题各不相同
  • 色彩对比度足够高
  • 语义 HTML 可确保逻辑交互
  • 屏幕阅读器可使用所有控件
  • 滑块使用 ARIA 属性提供标签
  • 颜色选择器具有正确的焦点陷阱
  • 播报更改、错误和通知
  • 高对比度模式已启用

恭喜!您解决了 Angular 应用中常见的网络无障碍功能问题!🎉

要查看所有解决方案,请查看 main 分支。

147ed8c9c57b3a2.png 2044559004149c85.png 4d594c26474fe97.png

现在,您已知道解决 Angular 应用中八个常见的 a11y 问题所需的关键步骤。

了解详情

查看以下 Codelab:

请阅读以下资料: