codecamp

Angular 无障碍性

Angular 中的无障碍功能

Web 会被各种各样的人使用,包括有视觉或运动障碍的人。有多种辅助技术能使这些人更轻松地和基于 Web 的软件应用进行交互。另外,将应用设计得更易于访问通常也能改善所有用户的体验。

关于如何设计无障碍应用的问题和技术的深入介绍,参阅 Google 网络基础知识无障碍功能部分。

本页讨论了设计 Angular 应用的最佳实践,这些实践对所有用户(包括依赖辅助技术的用户)都适用。

本页中所讲的范例程序,参阅现场演练 / 下载范例

无障碍属性(Attribute)

建立无障碍的 Web 体验通常会涉及设置 ARIA 属性(Attribute) 以提供可能会丢失的语义。使用 Attribute 绑定模板语法来控制与无障碍性相关的属性(Attribute)值。

在 Angular 中绑定 ARIA 属性(Attribute)时,必须使用 ​attr.​ 前缀,因为 ARIA 规范针对的是 HTML 属性(Attribute),而不是 DOM 元素的属性(Property)。

<!-- Use attr. when binding to an ARIA attribute -->
<button [attr.aria-label]="myActionLabel">…</button>
注意
此语法仅对于属性(Attribute)绑定是必需的。静态 ARIA 属性(Attribute)不需要额外的语法。
<!-- Static ARIA attributes require no extra syntax -->
<button aria-label="Save document">…</button>

按照约定,HTML 属性(Attribute)使用小写名称(​tabindex​),而 Property 使用 camelCase 名称(​tabIndex​)。

Angular UI 组件

由 Angular 团队维护的 Angular Material 库是旨在提供完全无障碍的一组可复用 UI 组件。组件开发工具包(CDK)中包括 a11y 软件包,该软件包提供了支持无障碍领域的各种工具。比如:

  • LiveAnnouncer ​用于使用 ​aria-live​ 区域向屏幕阅读器用户朗读消息。关于 aria-live 领域的更多信息,参阅 W3C 文档。
  • cdkTrapFocus ​指令能将 Tab 键焦点捕获在元素内。使用它可为必须限制焦点的模态对话框之类的组件创建无障碍体验。

关于这些工具和其它工具的完整详细信息,参阅 Angular CDK 无障碍功能概述

增强原生元素

原生 HTML 元素捕获了许多对无障碍性很重要的标准交互模式。在制作 Angular 组件时,应尽可能直接复用这些原生元素,而不是重新实现已获良好支持的行为。

比如,你可以创建一个组件,它使用属性(Attribute)选择器指向原生 ​<button>​ 元素,而不是为各种新按钮创建自定义元素。通常这适用于 ​<button>​ 和 ​<a>​,但也可以用于许多其它类型的元素。

你可以在 Angular Material 中看到此模式的范例:MatButtonMatTabNavMatTable

将容器用于原生元素

有时要使用的原生元素需要一个容器元素。比如,原生 ​<input>​ 元素不能有子元素,因此任何自定义的文本输入组件都需要用其它元素来包装 ​<input>​。尽管你可能只在自定义组件的模板中包含 ​<input>​,但这将使该组件的用户无法为 ​input ​元素设置任意 Property 和 Attribute。相反,你可以创建一个使用内容投影的容器组件,以将原生控件包含在组件的 API 中。

你可以把 MatFormField 作为该模式的例子。

案例研究:构建自定义进度条

以下范例显示如何通过使用宿主(host)绑定来控制与无障碍性相关的属性(Attribute),来把进度条无障碍化。

  • 该组件使用标准的 HTML 属性(Attribute)​role ​和 ARIA 属性(Attribute)来定义要启用无障碍支持的元素。ARIA 属性(Attribute)​aria-valuenow​ 绑定到用户的输入。
  • import { Component, Input } from '@angular/core';
    
    /**
     * Example progressbar component.
     */
    @Component({
      selector: 'app-example-progressbar',
      template: '<div class="bar" [style.width.%]="value"></div>',
      styleUrls: ['./progress-bar.component.css'],
      host: {
        // Sets the role for this component to "progressbar"
        role: 'progressbar',
    
        // Sets the minimum and maximum values for the progressbar role.
        'aria-valuemin': '0',
        'aria-valuemax': '100',
    
        // Binding that updates the current value of the progressbar.
        '[attr.aria-valuenow]': 'value',
      }
    })
    export class ExampleProgressbarComponent  {
      /** Current value of the progressbar. */
      @Input() value = 0;
    }
  • 在模板中,​aria-label​ 属性(Attribute)可以确保屏幕阅读器能访问该控件。
  • <label>
      Enter an example progress value
      <input type="number" min="0" max="100"
          [value]="progress" (input)="setProgress($event)">
    </label>
    
    <!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
    <app-example-progressbar [value]="progress" aria-label="Example of a progress bar">
    </app-example-progressbar>

路由

导航后的焦点管理

在设计无障碍性时,在 UI 中跟踪和控制焦点是很重要的考虑因素。使用 Angular 路由时,你需要确定页面焦点在导航上的位置。

为了避免仅仅依靠视觉提示,你需要确保路由代码会在页面导航之后更新焦点。使用 ​Router ​服务中的 ​NavigationEnd ​事件可以知道何时该更新焦点。

以下范例显示了导航后如何在 DOM 中查找并把焦点移动到主体内容的头部。

router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
  const mainHeader = document.querySelector('#main-content-header')
  if (mainHeader) {
    mainHeader.focus();
  }
});

在实际的应用程序中,哪些元素获得焦点将取决于该应用特有的结构和布局。获得焦点的元素应使用户能够立即移动到刚刚进入视野的主要内容。你应该避免当路由变化后焦点重新回到 ​body ​元素的情况。

活动链接标识

用在活跃 ​RouterLink ​元素上的 CSS 类(一般通过 ​RouterLinkActive ​来指定)提供了有关哪个链接正处于活跃状态的视觉指示。此类指示不适用于盲人或视障用户,为了提供此类信息,还要将 ​aria-current​ 属性应用于此元素(有关更多信息,参阅MDN aria-current)。

RouterLinkActive ​指令提供了 ​ariaCurrentWhenActive ​输入属性,该输入属性会在链接变为活跃状态时将 ​aria-current​ 设置为指定的值。

以下示例展示了如何将 ​active-page​ 类应用于活跃链接,以及如何在它们处于活跃状态时将它们的 ​aria-current​ 属性设置为 ​"page"​ :

<nav>
  <a routerLink="home"
     routerLinkActive="active-page"
     ariaCurrentWhenActive="page">
    Home
  </a>
  <a routerLink="about"
     routerLinkActive="active-page"
     ariaCurrentWhenActive="page">
    About
  </a>
  <a routerLink="shop"
     routerLinkActive="active-page"
     ariaCurrentWhenActive="page">
    Shop
  </a>
</nav>


Angular 安全
Angular 保持最新
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

Angular 开发指南

Angular 特性预览

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }