アクセシビリティを考慮したアコーディオンを実装する

アコーディオンの実装をすることはよくありますが、アクセシビリティを考慮した場合の実装についてあまり意識したことがなかったので、W3Cのページを参考に考えてみます。

対応前

まずはアクセシビリティを特に考慮しないで実装してみます。

<div class="accordion js-accordion">
  <div class="accordion-header is-open" data-acc_header="acc-panel01">
    リゼ・ヘルエスタ
    <span class="accordion-header_icon"></span>
  </div>
  <div class="accordion-panel is-open" data-acc_panel="acc-panel01">
    <p>ヘルエスタ王国の第二皇女。<br>
      文武両道学園主席、真面目で誰にでも優しくかなりの人望がある。<br>
      王位継承の資格者として日々鍛錬や人とのコミュニケーションを大事にしている。</p>
    <p>ファンアート:<a href="https://twitter.com/hashtag/%E3%83%98%E3%83%AB%E7%B5%B5%E3%82%B9%E3%82%BF">#ヘル絵スタ</a></p>
  </div>

  ~ 略 ~
</div>

CSSは実装で必要な部分のみ抜粋しています。
全体のCSSはデモページでご確認ください。

.accordion-header {
  cursor: pointer;
}
.accordion-header.is-open .accordion-header_icon {
  rotate: -135deg;
}
.accordion-panel {
  display: none;
}
.accordion-panel.is-open {
  display: block;
}

.accordion-headerのクリックでアコーディオンが開閉され、アコーディオンのスイッチとパネルの紐づけはdata-acc_headerとdata-acc_panelの属性で行う想定です。
アコーディオンが開いている場合は.accordion-headerと.accordion-panelに対して.is-openが付与され、このクラスを使ってアイコンの切り替えとパネルの開閉が行われます。

JavaScriptで開閉処理を実装します。

const accordionButtons = document.querySelectorAll('.js-accordion [data-acc_header]');
accordionButtons.forEach((accordionButton) => {
  accordionButton.addEventListener('click', (e) => {
    // アコーディオンの要素取得
    const header = e.currentTarget;
    const accordionId = header.getAttribute('data-acc_header');
    const panel = document.querySelector(`[data-acc_panel = "${accordionId}"]`);

    // DOMの更新
    header.classList.toggle('is-open');
    panel.classList.toggle('is-open');
  });
});

これでアコーディオンの実装ができました。
アクセシビリティ対応前のアコーディオンのデモページ

キーボード操作の対応

前のデモを元にアクセシビリティに考慮した実装を考えてみますが、まずアコーディオンのスイッチにTabキーでフォーカスできない点が問題です。
またスイッチにフォーカスできないため、EnterキーやSpaceキーでのアコーディオンの開閉も行えません。

キーボードでの操作に関しては、参考ページでも以下のように記載されています。

  • Enter or Space:
    • When focus is on the accordion header for a collapsed panel, expands the associated panel.If the implementation allows only one panel to be expanded, and if another panel is expanded, collapses that panel.
    • When focus is on the accordion header for an expanded panel, collapses the panel if the implementation supports collapsing.Some implementations require one panel to be expanded at all times and allow only one panel to be expanded; so, they do not support a collapse function.
  • Tab: Moves focus to the next focusable element; all focusable elements in the accordion are included in the page Tab sequence.

引用 – Accordion Pattern (Sections With Show/Hide Functionality) | APG | WAI | W3C

この対応として、スイッチ部分にbuttonタグを使用することでTabキーでフォーカスが当たるようになり、EnterキーやSpaceキーでの開閉もできるようになります。
.accordion-header部分をbuttonタグに変更するでもよさそうですが、以下の引用に記載されているように、スイッチ部分にはbuttonのロールを持った要素を含めた上で、headingのロールを持った要素でラップするのがいいようです。

  • The title of each accordion header is contained in an element with role button.
  • Each accordion header button is wrapped in an element with role heading that has a value set for aria-level that is appropriate for the information architecture of the page.
    • If the native host language has an element with an implicit heading and aria-level, such as an HTML heading tag, a native host language element may be used.
    • The button element is the only element inside the heading element. That is, if there are other visually persistent elements, they are not included inside the heading element.

引用 – Accordion Pattern (Sections With Show/Hide Functionality) | APG | WAI | W3C

アコーディオンのスイッチ部分を見出しタグとボタンタグに変更してみます。

<div class="accordion js-accordion">
  <h3 class="accordion-header">
    <button
      type="button"
      class="accordion-header_trigger is-open"
      data-acc_header="acc-panel01"
    >
      リゼ・ヘルエスタ
      <span class="accordion-header_icon"></span>
    </button>
  </h3>
  <div class="accordion-panel is-open" data-acc_panel="acc-panel01">
    <p>ヘルエスタ王国の第二皇女。<br>
      文武両道学園主席、真面目で誰にでも優しくかなりの人望がある。<br>
      王位継承の資格者として日々鍛錬や人とのコミュニケーションを大事にしている。</p>
    <p>ファンアート:<a href="https://twitter.com/hashtag/%E3%83%98%E3%83%AB%E7%B5%B5%E3%82%B9%E3%82%BF">#ヘル絵スタ</a></p>
  </div>

  ~ 略 ~
</div>

クリック対象を.accordion-headerから.accordion-header_trigger(buttonタグ)に変更します。

.accordion-header_trigger {
  cursor: pointer;
}
.accordion-header_trigger.is-open .accordion-header_icon {
  rotate: -135deg;
}

JavaScriptの変更はありません。
これでTabキーでのスイッチへのフォーカスと、EnterキーやSpaceキーでのアコーディオンの開閉ができるようになりました。
キーボード操作への対応のデモページ

WAI-ARIAの対応

次にWAI-ARIAの対応ですが、参考ページの以下の引用を参考に、スイッチ部分(buttonタグ)にaria-controls属性とaria-expanded属性の追加を行います。
aria-controls属性は制御対象(今回の場合は開閉するパネル)を識別するための属性で、aria-expanded属性は制御対象が展開されているかどうかを設定する属性になります。

  • If the accordion panel associated with an accordion header is visible, the header button element has aria-expanded set to true. If the panel is not visible, aria-expanded is set to false.
  • The accordion header button element has aria-controls set to the ID of the element containing the accordion panel content.
  • If the accordion panel associated with an accordion header is visible, and if the accordion does not permit the panel to be collapsed, the header button element has aria-disabled set to true.

引用 – Accordion Pattern (Sections With Show/Hide Functionality) | APG | WAI | W3C

合わせて参考ページにはありませんが、パネルの非表示の設定にaria-hidden属性を使うように変更してみます。

<div class="accordion js-accordion">
  <h3 class="accordion-header">
    <button
      type="button"
      aria-expanded="true"
      class="accordion-header_trigger"
      aria-controls="acc-panel01"
    >
      リゼ・ヘルエスタ
      <span class="accordion-header_icon"></span>
    </button>
  </h3>
  <div
    id="acc-panel01"
    class="accordion-panel"
    aria-hidden="false"
  >
    <p>ヘルエスタ王国の第二皇女。<br>
      文武両道学園主席、真面目で誰にでも優しくかなりの人望がある。<br>
      王位継承の資格者として日々鍛錬や人とのコミュニケーションを大事にしている。</p>
    <p>ファンアート:<a href="https://twitter.com/hashtag/%E3%83%98%E3%83%AB%E7%B5%B5%E3%82%B9%E3%82%BF">#ヘル絵スタ</a></p>
  </div>

  ~ 略 ~
</div>

スイッチに追加したaria-controls属性にはパネル要素のidを指定、aria-expanded属性はパネルが開いている場合はtrueを、閉じている場合はfalseを指定します。
パネルに追加したaria-hidden属性はaria-expanded属性と逆で、パネルが閉じている場合はtrueを、開いている場合はfalseを指定します。
スイッチとパネルの紐づけは今まではdata属性で行っていましたが、aria-controls属性でスイッチとパネルの紐づけを行うようになったので削除しました。

CSSは今まで.is-openの付与でスタイル変更していたのを、aria-expanded属性とaria-hidden属性の値によって変更するようにします。

.accordion-header_trigger[aria-expanded="true"] .accordion-header_icon {
  rotate: -135deg;
}
.accordion-panel[aria-hidden="true"] {
  display: none;
}

JavaScriptはdata属性とclass(.is-open)付与をしていた部分を、aria属性に変更します。

const accordionButtons = document.querySelectorAll('.js-accordion button[aria-expanded]');
accordionButtons.forEach((accordionButton) => {
  accordionButton.addEventListener('click', (e) => {
    // アコーディオンの要素取得
    const button = e.currentTarget;
    const accordionId = button.getAttribute('aria-controls');
    const panel = document.getElementById(accordionId);
    const currentExpanded = button.getAttribute('aria-expanded') === 'true';
    // アコーディオンの次の状態
    const nextExpanded = !currentExpanded;

    // DOMの更新
    button.setAttribute('aria-expanded', `${nextExpanded}`);
    panel.setAttribute('aria-hidden', `${!nextExpanded}`);
  });
});

これでWAI-ARIAの対応ができました。
WAI-ARIA対応のデモページ

スクリーンリーダーのPC-Talkerで確認したところ、対応前(2つ目のデモ)の場合は最初のアコーディオンのスイッチにフォーカスが当たった時の読み上げは「リゼ・ヘルエスタの 確認 見出しレベル3」で、対応後の場合は「リゼ・ヘルエスタの 確認 マイナス 展開 見出しレベル3」となり、アコーディオンの展開状態も含まれるようになりました。
アコーディオンが閉じている場合は「リゼ・ヘルエスタの 確認 プラス 折りたたみ 見出しレベル3」となります。

WAI-ARIAの対応(オプション)

参考ページでオプションとして記載されていますが、パネルにregionのロールの指定と、aria-labelledby属性でスイッチのbutton要素のidを指定することができます。

  • Optionally, each element that serves as a container for panel content has role region and aria-labelledby with a value that refers to the button that controls display of the panel.
    • Avoid using the region role in circumstances that create landmark region proliferation, e.g., in an accordion that contains more than approximately 6 panels that can be expanded at the same time.
    • Role region is especially helpful to the perception of structure by screen reader users when panels contain heading elements or a nested accordion.

引用 – Accordion Pattern (Sections With Show/Hide Functionality) | APG | WAI | W3C

regionのロールはスクリーンリーダー利用者が構造を認識するのに役立ちますが、アコーディオン数が多い場合(参考ページでは6つを超える場合)、ランドマーク領域が増えすぎてしまうのでregionのロール設定は避けた方がいいようです。

<div class="accordion js-accordion">
  <h3 class="accordion-header">
    <button
      type="button"
      aria-expanded="true"
      class="accordion-header_trigger"
      aria-controls="acc-panel01"
      id="acc-header01"
    >
      リゼ・ヘルエスタ
      <span class="accordion-header_icon"></span>
    </button>
  </h3>
  <div
    id="acc-panel01"
    role="region"
    aria-labelledby="acc-header01"
    class="accordion-panel"
    aria-hidden="false"
  >
    <p>ヘルエスタ王国の第二皇女。<br>
      文武両道学園主席、真面目で誰にでも優しくかなりの人望がある。<br>
      王位継承の資格者として日々鍛錬や人とのコミュニケーションを大事にしている。</p>
    <p>ファンアート:<a href="https://twitter.com/hashtag/%E3%83%98%E3%83%AB%E7%B5%B5%E3%82%B9%E3%82%BF">#ヘル絵スタ</a></p>
  </div>

  ~ 略 ~
</div>

regionのロール設定のデモページ

参考サイト

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2024年7月
 123456
78910111213
14151617181920
21222324252627
28293031