We're looking for a user researcher to understand the needs of developers and designers. Is this you or someone you know? Check out the post: https://mzl.la/2IGzdXS

この記事は翻訳作業中です。

前回の記事に続いて言えることですが、セマンティックではない HTML や JavaScript によって更新される動的なコンテンツを含むような、複雑な UI コントロールの作成は難しくなることがあります。WAI-ARIA は、ブラウザや assistive technology が認識可能な追加のセマンティックを追加することによってそのような問題に対処し、ユーザーの理解を助けます。ここでは、アクセシビリティを向上させるための基本的な使い方を説明します。

前提知識: 基本的なコンピューターの知識、 HTML 、 CSS 、 JavaScript に対する基本的な理解、 前回の記事に対する理解
学習目標: WAI-ARIA、および、アクセスビリティを向上させるために必要に応じて有用な追加のセマンティックを提供する方法について知識を得ること

WAI-ARIA って何?

まずは、WAI-ARIA とは何か、そして何ができるのかという点から始めましょう。

全く新しい問題

Web アプリがより複雑で動的なものになると、新しいアクセシビリティの機能と問題が明らかになってきます。

例えば、 HTML5 は普遍的なページの機能を定義するためにいくつものセマンティック要素を取り入れました。 (<nav><footer> 等) これらが利用可能になる以前は、開発者は  <div class="nav"> のように単に <div> を ID や class と共に使っていましたが、メインナビゲーションのようなページ内の機能をプログラムで識別する簡単な方法が無いために問題がありました。

初期の解決方法は、ナビゲーションへとリンクさせるため、以下のようにページ上部に1つ以上の隠しリンク (もしくは他の何か) を追加することでした。

<a href="#hidden" class="hidden">Skip to navigation</a>

しかしこれは簡潔な方法ではない上に、スクリーンリーダーがページ上部から読み込む場合にのみ利用できるものでした。

他の例としては、アプリが日付選択のための date picker や値選択のためのスライダーなどの複雑なコントロールを使いだしたケースがあります。HTML5 は、そのようなコントロールをレンダリングするための特別な input タイプを提供しています。

<input type="date">
<input type="range">

これらはブラウザ間で十分にサポートされておらず、またスタイル付けすることが非常に困難であるため、ウェブサイトのデザインに合わせる上で不便となります。結果として、開発者は多くの場合 JavaScript ライブラリを利用して複数のネストされた <div> でそのようなコントロールを生成したり、class 名を持った table 要素に対して CSS によるスタイル付けと JavaScript によるコントロールを行ったりします。

この場合の問題は、見た目上は動作するものの、スクリーンリーダーはそれらが何なのか全く理解できず、ユーザーは意味を成さないごちゃごちゃの要素であるとしか教えられないという点にあります。

WAI-ARIA の導入

WAI-ARIA は W3C によって定められた仕様で、追加のセマンティックを提供するために要素に対して適用可能な一連の HTML 属性を定義しており、どのような場所でもアクセシビリティを向上させます。この仕様では、主に3つの機能があります:

  • Roles — これは要素が何か、もしくは何をするかを定義します。多くの場合はいわゆる landmark roles であり、主に HTML5 構造要素のセマンティックを複製します。例えば、 role="navigation" (<nav>) や role="complementary" (<aside>) などです。しかし、それ以外にも別のページ構造を定義するものもあります。例えば、 role="banner" 、 role="search", role="tabgroup" 、 role="tab" 等で、 UIに多く見られます。
  • Properties — これは要素の性質を定義するものであり、追加の意味やセマンティックを与えるために使用することができます。例えば、 aria-required="true" はフォーム input が有効となるために値を入力しなければならないことを定義し、 aria-labelledby="label" は、要素にIDを追加することで、複数の場合も含めてページ内の他のどの要素からも label として参照することを可能にします。これは <label for="input"> ではできません。 別の例として、 aria-labelledby を使ってキーとなる記述を含む <div> が複数の table のセルの label であると指定することができますし、画像の代替テキストの代わりとして使用することもできます。これは、 alt 属性で繰り返すのではなく、ページの既存の情報を画像の代替テキストとして指定します。 代替テキスト で例を確認することができます。
  • States — 要素の現在の状態を定義する特別なプロパティです。例えば、 aria-disabled="true" は、フォームの input が現在 disabled であることをスクリーンリーダーに対して伝えます。states は properties とな異なり、properties はアプリのライフサイクルを通して変化しないのに対して、 states は主にJavaScriptによって変更されます。

WAI-ARIA 属性の重要な点は、ブラウザのアクセシビリティAPI (スクリーンリーダーはここから情報を取得する) によって提供される情報を除いて、それらはウェブページに何の影響も与えないという点です。WAI-ARIA はウェブページの構造や DOM に影響を与えませんが、 CSSの要素選択で利用することが可能です。

: WAI-ARIA の仕様で、ARIA roles の使用方法と追加情報へのリンクを含む便利なリストを確認することができます。 Definition of Roles を見てください。

この仕様では、properties と states の追加情報を含んだリストも確認することができます。 Definitions of States and Properties (all aria-* attributes) を見て下さい。

WAI-ARIA はどこでサポートされていますか?

この質問に答えるのは簡単ではありません。以下理由より、どこで、WAI-ARIA のどの機能がサポートされているのかを記述する決定的なりソースを見つけることが難しいためです。

  1. WAI-ARIA には大量の機能がある
  2. 検討しなければいけないオペレーティングシステム、ブラウザ、スクリーンリーダーの組み合わせが大量にある

最後の点は重要です。そもそもスクリーンリーダーを使用するためには、オペレーティングシステムが所定のアクセシビリティ API を持つブラウザを動作させる必要があり、それはスクリーンリーダーが動作するために必要となる情報を提供しなければいけません。ほとんどの人気の OS は、スクリーンリーダーが動作可能である1つか2つの所定のブラウザを持っています。Paciello Group は、この件に関してほぼ最新のデータを投稿しています。 Rough Guide: browsers, operating systems and screen reader support updated を見て下さい。

次に、ブラウザが問題となっている ARIA の機能をサポートしているのか、および API を通してそれらを公開しているのかという点を気にする必要があります。しかし、スクリーンリーダーがそれらの情報を認識し、意味のある形でユーザーに伝えているのかという点もまた気にしなければいけません。

  1. ブラウザのサポート状況は概ね良いです。本記事の執筆時点で、 caniuse.com は全体のブラウザの WAI-ARIA のサポート状況は88%だとしています。
  2. スクリーンリーダーの ARIA のサポート状況はそこまでではありませんが、多くの一般的なスクリーンリーダーはそれに近いものになってきています。Powermapper による WAI-ARIA Screen reader compatibility の記事で、サポート状況を確認することができます。

この記事では、全ての WAI-ARIA の機能と詳細についてカバーするわけではありません。代わりに、あなたが知るべき最も重要な WAI-ARIA の機能についてカバーします。もしサポートの詳細について何も記述してしない場合は、その機能が十分にサポートされていると想定してください。この例外がある場合は、明確に記述します。 

: JavaScript ライブラリには WAI-ARIA をサポートしているものがありますが、それはライブラリが複雑なフォームコントロールのような UI を生成した場合に、アクセシビリティを向上させるための ARIA 属性を追加することを意味します。迅速なUI開発のためにサードパーティーの JavaScript ライブラリを探しているのであれば、その決断を下す際、UIのアクセシビリティのサポートを重要な要素として必ず考慮すべきです。良い例としては、 jQuery UI (About jQuery UI: Deep accessibility support を見て下さい)、 ExtJS 、 Dojo/Dijit があります。

いつ WAI-ARIA を使うべき?

私達は WAI-ARIA が作られるに至ったいくつかの問題について最初の方で話しましたが、基本的には WAI-ARIA が有用となる4つの主な場面があります。

  1. 道しるべ/ランドマーク (Signposts/Landmarks): ARIA の role 属性の値は、HTML 要素のセマンティック (例: <nav>) を再現する Landmark として振る舞ったり、 search 、 tabgroup 、 tab 、 listbox のようにHTML5 セマンティックの範囲外となる道しるべ (signpost) を異なる機能エリアに提供することができます。
  2. 動的なコンテンツの更新: スクリーンリーダーは、コンスタントに更新されるコンテンツが得意ではない傾向があります。ARIA の aria-live を使うことで、 XMLHttpRequest や DOM API を通してコンテンツが更新された場合に、スクリーンリーダーのユーザーに対してそれを伝えることができます。
  3. キーボードのアクセシビリティの向上: キーボードのアクセシビリティを最初から持つ HTML 要素がありますが、 JavaScript を使ってそれ以外の要素に同じようなインタラクションをさせる場合、スクリーンリーダーにとって困難が生じます。こうしなければならない場合、 WAI-ARIA は他の要素に対してフォーカスを得る手段を提供しています。  (tabindex の使用).
  4. セマンティックではないコントロールのアクセサビリティ: ネストした一連の <div> が CSS/JavaScript と共に複雑な UI 機能を構成していたり、ネイティブのコントロールが JavaScriptによって大きく強化/変更されている場合、アクセシビリティの提供は困難になります。そこにセマンティックや手がかりが無ければ、スクリーンリーダーのユーザーはその機能が何をするのか判断するのが難しくなるでしょう。このような状況では、 button 、 listbox 、または tabgroup といった role の組み合わせ、もしくは aria-required や aria-posinset などの property により機能の手がかりを提供することで、 ARIA は足りないものを補うことができます。

一点忘れてはいけないのが、 WAI-ARIA は必要な場合のみ使用するという点です。理想的には、スクリーンリーダーのユーザーの理解に必要となるセマンティックの提供は、常に ネイティブの HTML 機能  を使用して行うべきです。しかし、コードの制御が限定されていたり、 HTML 要素への実装が容易ではない複雑なものを作っているなどの理由で、これが困難となるケースがあります。そのような場合、 WAI-ARIA はアクセシビリティを向上させる上で価値のあるツールとなります。

もう一度言いますが、必要な時だけ使って下さい!

: 実際のユーザーによってあなたのサイトをテストすることも忘れないでください。障害のあるユーザーではなく、スクリーンリーダーを使用するユーザー、キーボードナビゲーションを使用するユーザーなどです。どれだけうまく動作するかという点で、彼らはあなたよりもうまく観察してくれるでしょう。 

実際的な WAI-ARIA の実装

次のセクションでは、実際の例と共に、より詳細な4つのエリアを見てみます。続行する前に、これから見る例をテストできるように、スクリーンリーダーのテスト環境を用意してください。 

詳細は スクリーンリーダーのテスト を確認してください。

道しるべ/ランドマーク (Signposts/Landmarks)

WAI-ARIA は role 属性 をブラウザに追加することで、必要に応じてあなたのサイトに付加的なセマンティックの値を追加することができます。これが有用となる最初の領域は、スクリーンリーダーのユーザーが共通のページ要素を見つけることができるようになる情報の提供です。例を見てみましょう。私達の website-no-roles の例 (実際の動作) は、以下の構造を持っています。

<header>
  <h1>...</h1>
  <nav>
    <ul>...</ul>
    <form>
      <!-- search form  -->
    </form>
  </nav>
</header>

<main>
  <article>...</article>
  <aside>...</aside>
</main>

<footer>...</footer>

もしあなたがモダンなブラウザでスクリーンリーダーのテストをした場合、いくつかの有用な情報を手に入れるでしょう。例えば、 VoiceOver は以下の内容を読み上げます:

  • <header> 要素の上 — "banner, 2 items" (ヘディングと <nav> を含んでいる)
  • <nav> 要素の上 — "navigation 2 items" (リストとフォームを含む)
  • <main> 要素の上 — "main 2 items" (articleとasideを含む)
  • <aside> 要素の上 — "complementary 2 items" (ヘディングとリストを含む)
  • 検索フォーム入力の上 — "Search query, insertion at beginning of text"
  • <footer> 要素の上 — "footer 1 item"

VoiceOver の Landmarks メニューを見ると (VoiceOver キー + U でアクセスし、カーソルキーでメニューを選択する) 、多くの要素が素早くアクセスできるように綺麗に並んでいることが確認できます。

しかし、これは改善することができます。検索フォームはユーザーが見つけたいと考える重要な Landmark ですが、ここでは Landmarks メニューの中に列挙されておらず、検索 input (<input type="search">) であるということ以上に目立つ Landmark としても扱われていません。 加えて、いくつかの古いブラウザ (特にIE8) は HTML5 要素のセマンティックを認識しません。

ARIA の機能を使用してこれを改善しましょう。まず、 HTMLに対していくつかの role 属性を追加します。私達のオリジナルファイルをコピーするか (index.html と style.css を参照) 、 website-aria-roles の例 (実際の動作) へ移動すると、以下の構造を確認できます:

<header>
  <h1>...</h1>
  <nav role="navigation">
    <ul>...</ul>
    <form role="search">
      <!-- search form  -->
    </form>
  </nav>
</header>

<main>
  <article role="article">...</article>
  <aside role="complementary">...</aside>
</main>

<footer>...</footer>

この例で、私達はあなたにボーナスの機能もあげました。<input> は aria-label 属性が設定されていますが、これは <label> 要素が含まれていない場合でもスクリーンリーダーによって読み上げられる説明ラベルを設定します。こういうケースでは、この機能はとても便利です。このような検索フォームはよくあるものであり、簡単に識別できるので、見えるラベルを設定するとデザインを台無しにしてしまうのです。

<input type="search" name="q" placeholder="Search query" aria-label="Search through site content">

さて、この例を VoiceOver で見た時、以下の改善を確認することができます:

  • ページをブラウジングした時と、 Landmarks メニューで見た時の両方において、検索フォームが分離したアイテムとして認識される
  • フォーム input がハイライトされた時、 aria-label に含まれているテキストが読み上げられる

さらに、このサイトは IE8 のような古いブラウザを使用しているユーザーにとってもアクセシブルとなる可能性が高いので、そのために ARIA role を含める価値もあります。そして、もしあなたのサイトが何らかの理由により <div> のみで構成されているなら、必要なセマンティックを提供するために確実に ARIA role を含めるべきです!

改善された検索フォームは、 HTML5 で利用できるセマンティック以上に ARIA が可能とすることを見せてくれました。あなたは以下の記事、特に Accessibility of non-semantic controls セクションで、より多くのセマンティックや ARIA のプロパティ/属性が持つ力を見ることがでしょう。まずは、 ARIA が動的コンテンツの更新をどのように助けるかを見てみましょう。

動的なコンテンツの更新

DOM に読み込まれたコンテンツ (本文の内容や、画像の代替テキストなど) はスクリーンリーダーを用いて容易にアクセスできます。従って、テキストコンテンツで作られた伝統的で静的なウェブサイトを、視覚的ハンディキャップを持つ人々にとってアクセシブルにすることは容易です。

問題はモダンなウェブアプリケーションが静的なテキストだけを使うことは少ないという点です。それらは動的に更新されるコンテンツ、すなわち、XMLHttpRequest, Fetch, or DOM APIs などの機構を通してページ全体をリロードすることなく更新を行うコンテンツで構成されることが多いです。このような箇所はしばしばライブリージョン (live regions) と呼ばれます。

簡単な例を見てみましょう。aria-no-live.html をご覧ください (もしくは 動作版をご覧ください)。この例では、ランダムに引用文を表示する1つの箱があります:

<section>
  <h1>Random quote</h1>
  <blockquote>
    <p></p>
  </blockquote>
</section>

JavaScript が XMLHttpRequest を通して JSON ファイルを読み込みます。この JSON ファイルには、複数のランダムな引用文とその著者が含まれています。読み込みの完了後に setInterval() ループを開始し、引用文の表示を10秒ごとに新しいものに切り替えます:

var intervalID = window.setInterval(showQuote, 10000);

これは正しく動作しますが、アクセシビリティとしてはよくありません。コンテンツの更新がスクリーンリーダーに検知されないため、ユーザーは何が起こっているかを知ることができないからです。これはつまらない例ですが、更新され続けるコンテンツを多く含む複雑なUIをあなたが作ることを想像してください (チャットルームや戦略ゲームのUI、動的に更新されるショッピングカートの表示など)。ユーザーに更新を知らせる何かしらの手段がない限り、それがどんなに実用的なアプリケーションであっても使いこなすことはできないでしょう。

幸いなことに WAI-ARIA はそのような通知を行う便利な機構を提供しています。それが aria-live プロパティです。このプロパティを要素に適用すると、スクリーンリーダーが更新されたコンテンツを読み上げてくれるようになります。どのような緊急性をもってコンテンツを読み上げてくれるかは、属性値によって変わります:

  • off: デフォルト値。更新は通知されない (should not)。
  • polite: 更新はユーザが暇になったときのみ通知される (should)。
  • assertive: 更新は可能な限り早くユーザに通知される (should)。
  • rude: ユーザを遮ることになったとしても、更新は即座に通知される (should)。

一般的に、発生した順に更新内容を読み上げるには assertive の設定で充分です。一度に複数の変更があっても、順次すべての更新内容が通知されます。rude の設定は、他の通知より優先すべき非常に高い優先度を持つ更新の場合にのみ使うべき (should) です。

aria-no-live.html と quotes.json のコピーを作成し、<section> タグの内容を以下のように更新してください:

<section aria-live="assertive">

これにより、コンテンツの更新があった際にスクリーンリーダーがその内容を読み上げてくれるようになります。

Note: file:// URLをもつページから XMLHttpRequest を呼び出そうとするとほとんどのブラウザはセキュリティ例外を投げます。たとえば、(ダブルクリックなどにより) ファイルを直接ブラウザで読み込んだ場合に file:// URLで開かれます。動作させるためには、 ウェブサーバー (GitHub を利用するなど) やローカルウェブサーバー (Python's SimpleHTTPServer など) にファイルをアップロードする必要があります。

加えて、考慮すべきことがあります。テキストの更新された部分だけを読み上げるべきかどうかです。常に見出し全体を読み上げる方が、何を読み上げられているかをユーザーが認識できるという点で望ましいかもしれません。その対象に aria-atomic プロパティを追加することで、このような動作を得ることができます。手元の <section> タグを再度更新して、以下のようにしてください:

<section aria-live="assertive" aria-atomic="true">

この aria-atomic="true" 属性が、更新された一部分だけではなく、要素の内容を1つのまとまりとして読み上げるようスクリーンリーダーに伝えます。

Note: 完成した例は aria-live.html をご覧ください (もしくは動作版をご覧ください)。

Note: aria-relevant プロパティは live region が更新された際に何が読み上げられるかを制御するのに非常に役に立ちます。たとえば、追加や削除をされた内容だけを読み上げさせることもできます。

キーボードでのアクセシビリティの拡張

このモジュールの他の箇所でも何度か言及したように、アクセシビリティという観点でのHTMLがもつ重要な能力の1つが、キーボードでのアクセシビリティが組み込まれていることです。キーボードから、ボタンやフォームコントロール、リンクなどの機能にアクセスできます。一般的に、タブキーでコントロール間を移動したり、エンター/リターンキーでコントロールの選択や活性化をしたり、必要に応じたその他の制御 (たとえば up や down カーソルでの <select> ボックス内のオプション間の移動) ができます。

しかし、時にはセマンティックでない要素 (ボタンや他のタイプのコントロール) や正しい用途ではないフォーカス可能な要素を利用するコードを書かざるをえないこともあるでしょう。あなたが引き継いだ作りの悪いコードを修正したり、そのようなコードを必要とする複雑なウィジェットを作ったりする場合があるかもしれません。

フォーカスできないコードをフォーカス可能にするために、WAI-ARIA では tabindex 属性を拡張していくつかの値を加えています:

  • tabindex="0" — 上で示したように、この値は通常タブキーでの移動対象とならない要素をタブ移動可能にします。この値は tabindex の値の中で最も便利なものです。
  • tabindex="-1" — この値は通常タブキーでの移動対象とならない要素がプログラム的にフォーカスを受け付けられるようにします。たとえば、JavaScript を利用したりリンクのターゲットとしてフォーカスするケースです。

より詳細な議論や典型的な実装例については、HTML のアクセシビリティに関する記事 —  Building keyboard accessibility back in をご覧ください。

セマンティックでないコントロールのアクセシビリティ

この節の内容は前節の続きです。多くの入れ子になった <div> 要素と CSS/JavaScript を利用して複雑な UI 機能を構築した場合、また、JavaScript で本来のコントロールの機能を拡張/改変した場合を考えてみましょう。そのようなときには、キーボードでのアクセシビリティが損なわれるだけでなく、スクリーンリーダーのユーザーが各機能のふるまいを理解することは何かの意味づけや手がかりがない限り困難となってしまう。そのような状況においても、ARIA はそこにあるべき意味を補足する手助けができます。

Form validation and error alerts

First of all, let's revisit the form example we first looked at in our CSS and JavaScript accessibility article (read Keeping it unobtrusive for a full recap). At the end of this section we showed that we have included some ARIA attributes on the error message box that apears when there are validation errors when you try to submit the form:

<div class="errors" role="alert" aria-relevant="all">
  <ul>
  </ul>
</div>
  • role="alert" automatically turns the element it is applied to into a live region, so changes to it are read out; it also semantically identifies it as an alert message (important time/context sensitive information), and represents a better, more accessible way of delivering an alert to a user (modal dialogs like alert() calls have a number of accessibility problems; see Popup Windows by WebAIM).
  • An aria-relevant value of all instructs the screenreader to read out the contents of the error list when any changes are made to it — i.e. when errors are added or removed. This is useful because the user will want to know what errors are left, not just what has been added or removed from the list.

We could go further with our ARIA usage, and provide some more validation help. How about indicating whether fields are required in the first place, and what range the age should be?

  1. At this point, take a copy of our form-validation.html and validation.js files, and save them in a local directory.
  2. Open them both in a text editor and have a look at how the code works.
  3. First of all, add a paragraph just above the opening <form> tag, like the one below, and mark both the form <label>s with an asterisk. This is normally how we mark required fields for sighted users.
    <p>Fields marked with an asterisk (*) are required.</p>
  4. This makes visual sense, but it isn't as easy to understand for screenreader users. Fortunately, WAI-ARIA provides the aria-required attribute to give screenreaders hints that they should tell users that form inputs need to be filled in. Update the <input> elements like so:
    <input type="text" name="name" id="name" aria-required="true">
    
    <input type="number" name="age" id="age" aria-required="true">
  5. If you save the example now and test it with a screenreader, you should hear something like "Enter your name star, required, edit text".
  6. It might also be useful if we give screenreader users and sighted users an idea of what the age value should be. This is often presented as a tooltip, or placeholder inside the form field perhaps. WAI-ARIA does include aria-valuemin and aria-valuemax properties to specify min and max values, but these currently don't seem very well supported; a better supported feature is the HTML5 placeholder attribute, which can contain a message that is shown in the input when no value is entered, and is read out by a number of screenreaders. Update your number input like this:
    <input type="number" name="age" id="age" placeholder="Enter 1 to 150" aria-required="true">

Note: You can see the finished example live at form-validation-updated.html.

WAI-ARIA also enables some advanced form labelling techniques, beyond the classic <label> element. We already talked about using the aria-label property to provide a label where we don't want the label to be visible to sighted users (see the Signposts/Landmarks section, above). There are some other labelling techniques that use other properties such as aria-labelledby if you want to designate a non-<label> element as a label or label multiple form inputs with the same label, and aria-describedby, if you want to associate other information with a form input and have it read out as well. See WebAIM's Advanced Form Labeling article for more details.

There are many other useful properties and states too, for indicating the status of form elements. For example, aria-disabled="true" can be used to indicate that a form field is disabled. Many browsers will just skip past disabled form fields, and they won't even be read out by screenreaders, but in some cases they will be perceived, so it is a good idea to include this attribute to let the screenreader know that a disabled input is in fact disabled.

If the disabled state of an input is likely to change, then it is also a good idea to indicate when it happens, and what the result is. For example, in our form-validation-checkbox-disabled.html demo there is a checkbox that when checked, enables another form input to allow further information be entered. We've set up a hidden live region:

<p class="hidden-alert" aria-live="assertive"></p>

which is hidden from view using absolute positioning. When this is checked/unchecked, we update the text inside the hidden live region to tell screenreader users what the result of checking this checkbox is, as well as updating the aria-disabled state, and some visual indicators too:

function toggleMusician(bool) {
  var instruItem = formItems[formItems.length-1];
  if(bool) {
    instruItem.input.disabled = false;
    instruItem.label.style.color = '#000';
    instruItem.input.setAttribute('aria-disabled', 'false');
    hiddenAlert.textContent = 'Instruments played field now enabled; use it to tell us what you play.';
  } else {
    instruItem.input.disabled = true;
    instruItem.label.style.color = '#999';
    instruItem.input.setAttribute('aria-disabled', 'true');
    instruItem.input.removeAttribute('aria-label');
    hiddenAlert.textContent = 'Instruments played field now disabled.';
  }
}

Describing non-semantic buttons as buttons

A few times in this course already, we've mentioned the native accessibilty of (and the accessibility issues behind using other elements to fake) buttons, links, or form elements (see UI controls in the HTML accessibility article, and Enhancing keyboard accessibility, above). Basically, you can add keyboard accessibility back in without too much trouble in many cases, using tabindex and a bit of JavaScript.

But what about screenreaders? They still won't see the elements as buttons. If we test our fake-div-buttons.html example in a screenreader, our fake buttons will be reported using phrases like "Click me!, group", which is obviously confusing.

We can fix this using a WAI-ARIA role. Make a local copy of fake-div-buttons.html, and add role="button" to each button <div>, for example:

<div data-message="This is from the first button" tabindex="0" role="button">Click me!</div>

Now when you try this using a screenreader, you'll have buttons be reported using phrases like "Click me!, button" — much better.

Note: Don't forget however that using the correct semantic element where possible is always better. If you want to create a button, and can use a <button> element, you should use a <button> element!

Guiding users through complex widgets

There are a whole host of other roles that can identify non-semantic element structures as common UI features that go beyond what's available in standard HTML, for example combobox, slider, tabpanel, tree. You can see a number of userful examples in the Deque university code library, to give you an idea of how such controls can be made accessible.

Let's go through an example of our own. We'll return to our simple absolutely-positioned tabbed interface (see Hiding things in our CSS and JavaScript accessibility article), which you can find at Tabbed info box example (see source code).

This example as-is works fine in terms of keyboard accessibility — you can happily tab between the different tabs and select them to show the tab contents. It is also fairly accessible too — you can scroll through the content and use the headings to navigate , even if you can't see what is happening on screen. It is however not that obvious what the content is — a screenreader currently reports the content as a list of links, and some content with three headings. It doesn't give you any idea of what the relationship is between the content. Giving the user more clues as to the structure of the content is always good.

To improve things, we've created a new version of the example called aria-tabbed-info-box.html (see it running live). We've updated the structure of the tabbed interface like so:

<ul role="tablist">
  <li class="active" role="tab" aria-selected="true" aria-setsize="3" aria-posinset="1" tabindex="0">Tab 1</li>
  <li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="2" tabindex="0">Tab 2</li>
  <li role="tab" aria-selected="false" aria-setsize="3" aria-posinset="3" tabindex="0">Tab 3</li>
</ul>
<div class="panels">
  <article class="active-panel" role="tabpanel" aria-hidden="false">
    ...
  </article>
  <article role="tabpanel" aria-hidden="true">
    ...
  </article>
  <article role="tabpanel" aria-hidden="true">
    ...
  </article>
</div>

Note: The most striking change here is that we've removed the links that were originally present in the example, and just used the list items as the tabs — this was done because it makes things less confusing for screenreader users (the links don't really take you anywhere; they just change the view), and it allows the setsize/position in set features to work better — when these were put on the links, the browser kept reporting "1 of 1" all the time, not "1 of 3", "2 of 3", etc.

The new features are as follows:

  • New roles — tablist, tab, tabpanel — these identify the important areas of the tabbed interface — the container for the tabs, the tabs themselves, and the corresponding tabpanels.
  • aria-selected — Defines which tab is currently selected. As different tabs are selected by the user, the value of this attribute on the different tabs is updated via JavaScript.
  • aria-hidden — Hides an element from being read out by a screenreader. As different tabs are selected by the user, the value of this attribute on the different tabs is updated via JavaScript.
  • tabindex="0" — As we've removed the links, we need to give the list items this attribute to provide it with keyboard focus.
  • aria-setsize — This property allows you to specify to screenreaders that an element is part of a series, and how many items the series has.
  • aria-posinset — This property allows you to specify what position in a series an element is in. Along with aria-setsize, it provides a screenreader with enough information to tell you that you are currently on item "1 of 3", etc. In many cases, browsers should be able to infer this information from the element hierarchy, but it certainly helps to provide more clues.

In our tests, this new structure did serve to improve things overall. The tabs are now recognised as tabs (e.g. "tab" is spoken by the screenreader), the selected tab is indicated by "selected" being read out with the tab name, and the screenreader also tells you which tab number you are currently on. In addition, because of the aria-hidden settings (only the non-hidden tab ever has aria-hidden="false" set), the non-hidden content is the only one you can navigate down to, meaning the selected content is easier to find.

Note: If there is anything you explicitly don't want screen readers to read out, you can give them the aria-hidden="true"  attribute.

Summary

This article has by no means covered all that's available in WAI-ARIA, but it should have given you enough information to understand how to use it, and know some of the most common patterns you will encounter that require it.

See also

 

In this module

 

ドキュメントのタグと貢献者

このページの貢献者: masasnap, Tsuyoshi
最終更新者: masasnap,