実践Webアクセシビリティ

実践!アクセシブルなアコーディオンコンポーネントの実装

Tags: アコーディオン, アクセシビリティ, ARIA, キーボード操作, JavaScript

はじめに

Webサイトやアプリケーションにおいて、コンテンツを整理し、省スペースで表示するためにアコーディオンコンポーネントは広く利用されています。しかし、適切に実装されていないアコーディオンは、特定のユーザーグループにとって操作が困難になることがあります。特に、キーボードのみで操作するユーザーや、スクリーンリーダーを利用するユーザーは、アコーディオンの状態変化(開閉)を認識できなかったり、操作自体ができなかったりといった課題に直面する可能性があります。

本記事では、ウェブアクセシビリティの観点から、アクセシブルなアコーディオンコンポーネントを実装するための具体的な手順とポイントを、コード例を交えながら解説します。

なぜアコーディオンのアクセシビリティが必要なのか

アコーディオンコンポーネントにおけるアクセシビリティの課題は主に以下の点に集約されます。

  1. キーボード操作性: マウスを使用しないユーザーが、アコーディオンの各項目にフォーカスを移動させ、開閉操作をキーボードで行える必要があります。標準的なHTML要素(例: button)を使用しない場合、追加のJavaScriptによるキーボードイベントハンドリングが必要になります。
  2. 状態の伝達: アコーディオンの項目が「開いている」のか「閉じている」のか、現在の状態を視覚情報に依存しない形でユーザーに伝える必要があります。特にスクリーンリーダーユーザーにとって、この状態情報はコンテンツを理解する上で不可欠です。
  3. コンテンツへのアクセス: アコーディオンが閉じている状態でも、その中に含まれるコンテンツの概要を理解できることや、必要に応じてコンテンツへスムーズにアクセスできることが望ましいです。

これらの課題に対応することで、キーボードユーザー、スクリーンリーダーユーザー、認知障害のあるユーザーなど、より多くの人々がアコーディオン内のコンテンツへ問題なくアクセスできるようになります。

具体的な実装手順

ここでは、ボタン要素とWAI-ARIA属性を使用して、一般的なアコーディオンコンポーネントをアクセシブルに実装する手順を解説します。

1. 基本的なHTML構造

アコーディオンの各項目は、見出しとなる要素(通常はボタン)とその内容パネルで構成されます。セマンティクスを考慮し、ボタン要素をトリガーにすることが推奨されます。

<div class="accordion">
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button" type="button" aria-expanded="false" aria-controls="section1">
        セクション1のタイトル
      </button>
    </h2>
    <div id="section1" class="accordion-content" role="region" aria-labelledby="section1-header" hidden>
      <!-- セクション1の内容 -->
      <p>ここにセクション1の詳細な内容が入ります。</p>
    </div>
  </div>

  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button" type="button" aria-expanded="false" aria-controls="section2">
        セクション2のタイトル
      </button>
    </h2>
    <div id="section2" class="accordion-content" role="region" aria-labelledby="section2-header" hidden>
      <!-- セクション2の内容 -->
      <p>ここにセクション2の詳細な内容が入ります。</p>
    </div>
  </div>

  <!-- 他のaccordion-itemも同様に記述 -->
</div>

2. CSSによるスタイリング

アコーディオンの見た目を整え、開閉状態を視覚的に表現します。また、キーボードフォーカスインジケーターを明確に表示することも重要です。

/* 基本スタイル */
.accordion-button {
  /* buttonのデフォルトスタイルをリセットする場合 */
  background: none;
  border: none;
  padding: 10px;
  width: 100%; /* 親要素の幅に合わせる */
  text-align: left;
  cursor: pointer;
  font-size: 1em;
  /* その他のスタイル(色、マージンなど) */
}

/* フォーカスインジケーター */
.accordion-button:focus {
  outline: 2px solid blue; /* または好みのスタイル */
  outline-offset: 2px;
}

/* 開閉状態によるスタイル */
.accordion-button[aria-expanded="true"] {
  font-weight: bold; /* 開いている状態のタイトルを太字にするなど */
}

.accordion-content {
  padding: 10px;
  border-top: 1px solid #ccc; /* パネルの区切り線 */
}

/* 初期状態または閉じている状態 */
.accordion-content[hidden] {
  display: none;
}

/* 開いている状態 */
.accordion-button[aria-expanded="true"] + .accordion-content {
  display: block;
}

3. JavaScriptによる開閉機能の実装

ボタンクリック時やキーボード操作時に、内容パネルの表示/非表示を切り替え、aria-expanded 属性の値を更新します。

document.addEventListener('DOMContentLoaded', () => {
  const buttons = document.querySelectorAll('.accordion-button');

  buttons.forEach(button => {
    const content = document.getElementById(button.getAttribute('aria-controls'));
    if (!content) {
      console.error(`対応するコンテンツが見つかりません: ${button.getAttribute('aria-controls')}`);
      return;
    }

    // 初期状態の設定(HTMLでhidden属性を付与している場合は不要な場合も)
    // button.setAttribute('aria-expanded', 'false');
    // content.setAttribute('hidden', ''); // hidden属性または style.display = 'none'

    button.addEventListener('click', () => {
      const isExpanded = button.getAttribute('aria-expanded') === 'true';
      button.setAttribute('aria-expanded', String(!isExpanded));
      content.toggleAttribute('hidden', isExpanded);

      // (任意) 他のアコーディオン項目を閉じる場合
      // closeOtherAccordionItems(button);
    });

    // キーボード操作 (Enter/Space は button 要素のデフォルト動作で実行されるため、明示的なハンドリングは不要)
    // 必要に応じて、矢印キーでのフォーカス移動などを実装することも可能ですが、
    // シンプルなアコーディオンであれば Tab キー移動で十分な場合が多いです。
  });

  // (任意) 他のアコーディオン項目を閉じる関数
  function closeOtherAccordionItems(clickedButton) {
    buttons.forEach(button => {
      if (button !== clickedButton && button.getAttribute('aria-expanded') === 'true') {
        const contentToClose = document.getElementById(button.getAttribute('aria-controls'));
        button.setAttribute('aria-expanded', 'false');
        contentToClose.setAttribute('hidden', '');
      }
    });
  }
});

実装時の注意点

テスト方法

実装したアコーディオンがアクセシブルであるかを確認するために、以下のテストを行います。

  1. キーボード操作:
    • Tabキーを使って、ページ内のアコーディオンの各タイトル(ボタン)にフォーカスが移動することを確認します。
    • フォーカスが当たっている状態でEnterキーまたはSpaceキーを押し、内容パネルが開閉することを確認します。
    • アコーディオンが開閉する際に、意図しないフォーカス移動が発生しないか確認します(コンテンツの先頭などに自動的に移動させたい場合は別ですが、多くの場合、トリガーボタンにフォーカスが維持されるのが自然です)。
  2. スクリーンリーダーでの確認:
    • VoiceOver (macOS/iOS), NVDA (Windows), JAWS (Windows) などのスクリーンリーダーを起動します。
    • Tabキーでアコーディオンのタイトル(ボタン)に移動した際に、「セクション1のタイトル、折りたたみ済み、ボタン」(または同様の情報)のように、ボタンのラベルと開閉状態(折りたたみ済み/展開済み)が正しく読み上げられるか確認します。
    • Enter/Spaceキーで開閉操作を行った後、再度ボタンにフォーカスを戻すか、ページを移動して、状態の変化(「展開済み」への変化)が読み上げられるか確認します。
    • アコーディオンが開いた状態で、内容パネル内のコンテンツが正しく読み上げられるか確認します。
  3. アクセシビリティ評価ツールの利用:
    • ブラウザ拡張機能(Lighthouse, axe DevTools, WAVEなど)や、オンラインツールを使用して、ARIA属性の誤りやその他のアクセシビリティに関する問題を自動的にチェックします。ただし、これらのツールは全ての問題を検出できるわけではないため、手動での確認が不可欠です。

まとめ

アクセシブルなアコーディオンコンポーネントの実装は、HTMLのセマンティクス、適切なARIA属性の使用、そしてJavaScriptによるキーボード操作への対応が鍵となります。button 要素をトリガーとし、aria-expandedaria-controls を正しく設定し、キーボードフォーカスと視覚的な状態表示を明確にすることで、より多くのユーザーが快適に利用できるアコーディオンを提供できます。

本記事で紹介した手順とコード例を参考に、ご自身のプロジェクトにアクセシブルなアコーディオン実装を取り入れていただければ幸いです。どのようなコンポーネントにおいても、利用者の視点に立ち、様々な操作方法や環境を想定して設計・実装することが、アクセシビリティ対応の第一歩となります。