適切なユーザー補助機能が備わった Angular アプリを作成する

b23a30a52c1169e4.png

ユーザー補助機能はウェブ開発の不可欠な要素であり、ユーザーがアプリを認識、理解、ナビゲート、操作できるようにするものです。実際のところ、米国では成人の 4 人に 1 人が生活に支障をきたす障がいを抱えています。全世界では人口の約 15%、つまり 10 億人以上がなんらかの障がいを抱えていて、約 2~4% が大きな困難を経験しています。

個人のウェブの利用に影響する一般的な状態としては、目の見えない状態やロービジョン、聴覚障がいや難聴、運動機能の障がい、認知障がい、色覚異常などがありますが、これらは一部にすぎません。

このコースでは、a11y は accessibility(ユーザー補助)の略語です。a の後に 11 文字が続き末尾が y であるためこのように略します。

適切なユーザー補助機能が備わったアプリを設計する際の問題やテクニックについて詳しくは、ユーザー補助をご覧ください。

作成するアプリの概要

  • ダンプリング料理店の Angular アプリをデモとして取り上げ、ベスト プラクティスと組み込み済みの手法を使用してウェブのユーザー補助の一般的な問題に取り組みます。
  • ユーザー補助のすべてのガイドライン(WCAG 2.0 と ARIA 1.2)を満たし、axe と Lighthouse のユーザー補助の監査に合格するようにします。

818cc91d17fae486.png 510ca511c265da81.png

学習する内容

Angular アプリでユーザーに影響する 8 つの一般的なユーザー補助の問題と、それらの特定方法と解決方法について学習します。具体的には、次の作業を行います。

  • Google Chrome デベロッパー ツール、Lighthouse、axe を使用して、アプリのユーザー補助を監査する
  • 固有のページタイトルを使用することによって、シングルページ アプリ(SPA)で陥りがちな問題を解決する
  • ロービジョンのユーザー向けに低コントラストの問題を修正する
  • セマンティック HTML を使用して、スクリーン リーダーでページを正しく移動できるようにする
  • Angular Material やネストしていないコントロールを使用して、スクリーン リーダーですべてのコントロールにアクセスできるようにする
  • スクリーン リーダー用の ARIA サポートを追加する
  • Angular CDK a11y パッケージをインポートして使用する
  • カスタム コンポーネントのスクリーン リーダー ナビゲーション用に FocusTrap を使用する
  • CDK LiveAnnouncer を使用して通知を音声で案内する
  • HighContrast モードを使用しているユーザーを検出して、ハイ コントラスト テーマを実装する

必要なもの

コードを取得する

このプロジェクトに必要なすべてのコードは GitHub リポジトリにあります。まず、コードをクローンし、お好みの開発環境で開きます。

リポジトリをクローンし、アプリ用のサーバーを起動する

この Codelab での作業には、VSCode またはローカルの IDE を使用することをおすすめします。

  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

デモを試してみる

まず、アプリの 3 つの機能を使ってみます。

  1. ナビゲーション バーで [Our Shop]、[Our Story]、[Find Us] のルートを表示し、このダンプリング料理会社の詳細情報を参照します。
  2. テーマを変更して、ライトモードとダークモードを切り替えます。
  3. 注文するダンプリングの具材、数量、色をカスタマイズします。
  4. [Purchase] を選択して、カスタマイズした注文をコンソールに出力します。

Angular を使用してウェブのユーザー補助の一般的な問題に対処する

この Codelab では、このアプリの既存機能のユーザー補助について重点的に見ていきます。まず、アプリの a11y の問題を特定し、解決策を実装することで 🛑 を ✅ にします。

修正すべき問題を確認する方法

まず、各サンプルで手動テストと自動テストを組み合わせて使用することで、ユーザー補助の問題を把握します。

ウェブの現在の状況を考えると、ユーザー補助の手動テストは必須です。

ユーザー補助の問題を特定できるツールはありますが、アプリのユーザー補助が完全であることを保証できるツールはありません。手動テストを行うことにより、コンテンツの論理的な順序や機能の同等性など、さまざまな a11y のコンセプトのテストが網羅できます。

手動テスト

このコースでユーザー補助を手動でテストするには、コンピュータに組み込まれているスクリーン リーダーをオンにして、キーボード ナビゲーションを使用してアプリ内を移動します。詳細については、セマンティクスとスクリーン リーダーをご覧ください。

スクリーン リーダーをオンにして画面内を移動し、実際に操作します。

macOS 内蔵の VoiceOver を使用することもできます。[システム環境設定] > [アクセシビリティ] > [VoiceOver] > [VoiceOver を有効にする] の順にクリックします。VoiceOver を切り替えるには、Command キーを押したまま Touch ID をすばやく 3 回押します。

このコースでは主に手動で問題をテストします。また、自動化ツールを使用して特定の自動化可能な機能のチェックを支援します。

自動テスト

複数の開発ツールを使用して、テストを自動化してアプリを監査することもできます。これらのツールを使用すると、画像に代替テキストがあるかどうかや、テキストの色のコントラスト比などを確認できます。これらのツールは linter のようなものです。代替テキストが存在するかどうかは認識できますが、その内容が論理的であり価値を提供するものであるかの確認は手動で行う必要があります。

Lighthouse と Chrome デベロッパー ツール

  1. Chrome デベロッパー ツールを開きます。
  2. [Lighthouse] タブを選択し、[Accessibility] チェックボックスをオンにします。
  3. [Generate report] をクリックして a11y Lighthouse 監査を実行します。

3935811012517f4e.png

axe

  1. axe DevTools 拡張機能をインストールします。拡張機能を表示するには、ブラウザの再起動が必要な場合があります。
  2. Chrome デベロッパー ツールを開きます。
  3. [axis DevTools] タブを選択し、[Scan all 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 には論理的な順序、名前、役割が必要である
  • 🛑 ネストしたチェックボックスはスクリーン リーダーでは選択できない
  • 🛑 スクリーン リーダーがスライダーの値を読み上げない
  • 🛑 カラー選択ツールでスクリーン リーダーのフォーカスがダイアログ外に出てしまう
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

固有の簡潔なページタイトルを使用すると、a11y サービスを使用するユーザーは、ウェブページのコンテンツと目的をすばやく理解できます。視覚障がいのあるユーザーにはページタイトルが非常に重要です。なぜなら、スクリーン リーダー ソフトウェアが音声で案内する最初のページ要素がページタイトルであるためです。

Angular はシングルページ アプリであるため、新しいページへの移動など、大部分の変遷ではページの再読み込みは行われません。つまり、初期状態のままでは、各ページは同一のページタイトルで読み上げられ、ページの内容や目的を理解するための値を提供しません。

このセクションを終了した時点で、アプリは次の監査で合格になります。

  • 🛑 すべてのページのタイトルが同じである

これらの各ステップは「TODO: #4. Define unique page titles.」のコメントの下にあります。

問題を特定する

この問題を特定するには、スクリーン リーダーをオンにして、[Our Shop] タブ、[Our Story] タブ、[Find Us] タブ間を移動してページタイトルを確認します。

  1. VoiceOver をオンにします。
  2. タブ ナビゲーションを使用してページ間を移動します。
  3. Angular でページタイトルが常に a11y であることを確認します。

ユーザーがページ内をすべて移動しなくてもページの内容をすぐに理解できるようにするには、ページタイトルが一意である必要があります。そのため、この点が問題になります。

cb92438126bb2be8.png

意味のあるページタイトルを追加する

ページまたはビューが変更された場合は、ページタイトルを適切に管理する必要があります。この問題を解決するには、Angular の Title サービスを使用して、各ページに固有のタイトルを定義します。

  1. 3 つの定義済みルートのそれぞれに固有のタイトルを追加します。

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 には論理的な順序、名前、役割が必要である
  • 🛑 ネストしたフルーツのチェックボックスはスクリーン リーダーでは選択できない
  • 🛑 スクリーン リーダーがスライダーの値を読み上げない
  • 🛑 カラー選択ツールでスクリーン リーダーのフォーカスがダイアログ外に出てしまう
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

「クール」なデザインを作成したとしても、色覚異常などの視覚障がいのあるユーザーがコンテンツを読み取れなければ、それはクールであるとは言えません。Web Content Accessibility Guidelines(WCAG 2.0)は、コンテンツがユーザー補助の条件を満たすための、一連の色のコントラスト比を定義しています。Angular とウェブで、コンポーネントがこれらの基準を満たし、ロービジョンや色覚異常のユーザーでも見やすいようにカラーパレットを定義できます。

このセクションを終了した時点で、アプリは次の監査で合格になります。

  • 🛑 要素には十分な色のコントラストが必要である

これらの各ステップは「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 には論理的な順序、名前、役割が必要である
  • 🛑 ネストしたフルーツのチェックボックスはスクリーン リーダーでは選択できない
  • 🛑 スクリーン リーダーがスライダーの値を読み上げない
  • 🛑 カラー選択ツールでスクリーン リーダーのフォーカスがダイアログ外に出てしまう
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

ネイティブの 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 によって論理的な操作ができる
  • 🛑 ネストしたサイズのチェックボックスはスクリーン リーダーでは選択できない
  • 🛑 スクリーン リーダーがスライダーの値を読み上げない
  • 🛑 カラー選択ツールでスクリーン リーダーのフォーカスがダイアログ外に出てしまう
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

ユーザー補助サービスの複雑な操作パターンの 1 つに、ネストしたコントロールがあります。メニューのサブアイテムやネストしたチェックボックスについて考えてみましょう。オプションのサブグループを選択できることや親メニュー項目に移動できることをユーザーに示すにはどうすればよいでしょうか?

Angular ではメニューとコントロールが単純化されます。コントロールをできる限り単純化することで、操作しやすいコンポーネントを作成します。この例では、Angular Material のリストボックスを使用して、この操作パターンの例を 1 つ作成します。

このセクションを終了した時点で、アプリは次の監査で合格になります。

  • 🛑 ネストしたサイズのチェックボックスはスクリーン リーダーでは選択できない

これらの各ステップは「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 を実装してしまうことも数多くあるため、手動でテストする必要があります。

チェックボックスを 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 を削除できる場所も示されています。不要な Sass を削除することによって、スタイルをクリーンアップできます。

変更の確認

スクリーン リーダーを再びオンにして、変更内容を確認します。スクリーン リーダーを使用してチェックボックスを選択できるようになり、より直感的に要素間を移動できるようになりました。

e9d473e1e7949442.png

ユーザー補助の監査:

  • すべてのページに固有のページタイトルがある
  • 色のコントラスト比が十分である
  • セマンティック HTML によって論理的な操作ができる
  • スクリーン リーダーによってすべてのコントロールにアクセスできる
  • 🛑 スクリーン リーダーがスライダーの値を読み上げない
  • 🛑 カラー選択ツールでスクリーン リーダーのフォーカスがダイアログ外に出てしまう
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

Angular アプリのセマンティック HTML と Material コンポーネントを変更しましたが、スクリーン リーダーによって完全にアクセスできるようにするには、一部のコンポーネントで特定の属性が必要になります。

Web Accessibility Initiative の Accessible Rich Internet Applications 仕様(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 属性を使用してラベルを提供している
  • 🛑 カラー選択ツールでスクリーン リーダーのフォーカスがダイアログ外に出てしまう
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

これまでは、一般的な a11y の問題の解決に、組み込みの Angular ツールを使用してきました。これからは、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、LiveAnnouncer、HighContrast の 3 つの一般的なサービスを追加します。

@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 属性を使用してラベルを提供している
  • カラー選択ツールに適切なフォーカス トラップが設定されている
  • 🛑 変更、エラー、通知が音声で案内されない
  • 🛑 HighContrast モードが有効になっていない

ページ上でなんらかの変化が起こった場合は、スクリーン リーダーへの通知が必要です。フォームを送信するとき、または購入を完了しようとするときに、エラーがポップアップ表示されてフォームを送信できないことがあります。ユーザーがその状況を把握できないと、大きなフラストレーションを感じます。

LiveAnnouncer は、スクリーン リーダーのユーザー向けに aria-live 領域を使用してメッセージを音声で案内するのに使用されます。この機能により、スクリーン リーダーは通知やライブページの変更を認識することができます。aria-live 領域の詳細については、W3C の WAI-ARIA をご覧ください。Angular では、aria-live 属性を使用するよりも、LiveAnnouncer をサービスとして呼び出す方がテストしやすいソリューションになります。

このセクションを終了した時点で、アプリは次の監査で合格になります。

  • 🛑 変更、エラー、通知が音声で案内されない

これらのステップは「TODO: #11. Announce changes with LiveAnnouncer.」のコメントの下にあります。

問題を特定する

この問題を特定するには、スクリーン リーダーをオンにして、フォームの項目に入力することなく [Purchase] を選択します。

  1. VoiceOver をオンにします。
  2. タブ ナビゲーションを使用して色を変更し、購入します(実際に購入が行われることはありません)。
  3. ダイアログの終了時にどの色が選択されていたかを示すものはないこと、購入は読み上げられないことに注意します。

8ec0de4079feaae7.png

コードに LiveAnnouncer を追加する

LiveAnnouncer を追加し、色の選択と購入の両方を文字列として音声で案内します。実際の実装では、サードパーティの支払いシステムに移動するときや、フォームでエラーが発生したときに読み上げが行われることがあります。

  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 属性を使用してラベルを提供している
  • カラー選択ツールに適切なフォーカス トラップが設定されている
  • 変更、エラー、通知が音声で案内される
  • 🛑 HighContrast モードが有効になっていない

Microsoft Windows は、ハイ コントラスト モードと呼ばれるユーザー補助機能をサポートしています。このモードでは、ウェブアプリを含むすべてのアプリの外観が変更され、コントラストが大幅に強くなります。Angular では、アプリでのユーザーの設定を考慮する必要があります。

HighContrastModeDetector を使用すると、ブラウザが現在ハイ コントラスト モード環境であるかどうかを判断できます。

Internet Explorer、Microsoft Edge、Firefox はこのモードをサポートしています。Google Chrome は Windows のハイ コントラスト モードをサポートしていません。このサービスは、Chrome の High Contrast ブラウザ拡張機能により追加されたハイ コントラスト モードを検出しません。

このセクションを終了した時点で、アプリは次の監査で合格になります。

  • 🛑 HighContrast モードが有効になっていない

これらのステップは「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 ミックスインを使用して、ボタンにハイ コントラスト モードのアウトラインを追加します。

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 アプリケーションで 8 つの一般的な a11y の問題を解決するのに必要な主要な手順を理解しました。

その他の情報

次の Codelab をご覧ください。

次の資料をご覧ください。