Topics

カード型コンポーネントのアクセシブルな実装パターン

  • column

記事一覧などでよく使うカード型コンポーネント。見た目はシンプルですが、アクセシビリティを考慮すると意外に奥深い設計課題があります。

典型的なカードとして上から

  • 画像
  • 記事タイトル
  • 記事の概要
  • 詳細リンク

と、縦に並ぶレイアウトでの実装パターンを考えてみましょう。

設計時の主な検討ポイント

1. 視覚順序とHTML構造

スクリーンリーダーは基本的にHTMLの記述順序で読み上げます。WCAG 2.0の達成基準1.3.2(意味のある順序、レベルA)では、視覚的な順序とHTML順序を一致させることが基本原則としています。

ただし、CSSで順序を変更すること自体がWCAG違反になるわけではありません。視覚的な順序とHTML順序が異なっても、コンテンツが理解可能であれば問題ありません。状況に応じて柔軟に判断することが重要です。

2. 画像の扱い方

記事カードの画像は、多くの場合装飾的です。記事タイトルがあれば内容は十分伝わるため、画像の説明を読み上げる必要性は低いと言えます。

装飾的画像として扱う場合alt=""だけで十分です。

<img src="thumbnail.jpg" alt="">

3. 詳細リンクのラベル

「詳細を見る」のような汎用的なテキストは、以下の理由で避けるべきです。

視覚的な問題

周辺のコンテキストなしでは、何のリンクか判断できない

スクリーンリーダーの問題

リンクリスト機能で一覧表示した際、すべて「詳細を見る」となり区別できない(WCAG 2.4.4 リンクの目的、レベルA)

音声認識の問題

複数の同じテキストがあると、番号での選択が必要になり操作が煩雑

理想的には「〇〇の詳細を見る」のように、リンク単体で目的が分かるテキストにすべきですが、ここでは「詳細を見る」というデザインをそのまま再現する場合の実装方法を扱います。

4. カードのクリッカブル領域

UX向上のため、カード全体をクリック可能にしたいケースがよくあります。実装方法は複数ありますが、それぞれアクセシビリティへの影響が異なります。

5. カードはarticleにするかdivにするか

どちらにするかは、コンテンツの性質によります。

<article>が適している場合:

  • カードの内容が独立したコンテンツとして成立する

<div>で問題ない場合:

  • 単なるリンクのグループとして機能する
  • カード自体に意味的な独立性がない

一般的なブログ記事一覧や商品一覧のカードでは、<article> が適切です。 ただし、複数の<article>を使用する場合は、スクリーンリーダーのランドマーク移動を考慮し、aria-labelledbyまたはaria-labelで各記事を識別できるようにすることが推奨されます(WCAG 2.4.6、レベルAA)。

aria-labelledby を使用する場合は、IDはユニークな値になるように注意してください。

視覚順序とHTML構造について

パターン1: 視覚的順序とHTML順序を一致させる

<article class="article-card" aria-labelledby="article-title">
  <img src="thumbnail.jpg" alt="">
  <h3 id="article-title"><a href="#" class="card-link">記事タイトル</a></h3>
  <p>記事の概要...</p>
  <a href="#" class="card-detail-link">
	  <span class="visually-hidden">記事タイトル:</span>詳細を見る
  </a>
</article>

HTMLの記述順序が視覚順序と完全に一致するため、シンプルで直感的です。

<article>の最初の要素は見出しが望ましいとされますが、絶対的な要件ではありません。 視覚順序との一致を優先する場合、このパターンで問題ありません。

補足:

音声認識ソフト(Dragon、Voice Controlなど)は画面に表示されているテキストを基準に動作します。 visually-hidden (sr-only)を使用することで視覚テキストが保持され、音声認識での操作が可能になります。 ほか、リンクラベルの対応でOKなパターンとNGなパターンの実装例です。

<!-- 以下は可視テキストがアクセシブルな名前に含まれているのでOK -->
<a href="#" id="link-text" class="card-detail-link" aria-labelledby="link-text article-title">
  詳細を見る
</a>
<a href="#" aria-label="詳細を見る:記事タイトル">
  詳細を見る
</a>
<!-- 以下は可視テキストがアクセシブルな名前に含まれていないのでNG -->
<a href="#" class="card-detail-link" aria-labelledby="article-title">
  詳細を見る
</a>
<a href="#" class="card-detail-link" aria-label="記事タイトル">
  詳細を見る
</a>

パターン2: CSS orderで視覚順序を調整

<article class="article-card" aria-labelledby="article-title">
  <h3 id="article-title"><a href="#">記事タイトル</a></h3>
  <p>記事の概要...</p>
  <a href="#" class="card-detail-link">
	  <span class="visually-hidden">記事タイトル:</span>詳細を見る
  </a>
  <img src="thumbnail.jpg" alt="">
</article>
.article-card {
  display: flex;
  flex-direction: column;
}

.article-card img {
  order: -1;
}

<article>の最初の要素が見出しになるため、セマンティック的により望ましい構造です。

装飾的画像(alt="")の場合、読み上げ順序への影響はありません(画像はスキップされるため)。

注意:

  • 画像が意味を持ち、alt属性を指定している場合、視覚順序と読み上げ順序が変わるためこの構造は適さない
  • キーボードのTab順序はHTMLの順序に従うため、カード内に複数のフォーカス可能な要素がある場合は、フォーカス順が論理的な流れを壊していないことを確認してください。

カードのクリッカブル領域を全体にしたい場合

パターン3: 擬似要素でカード全体をクリッカブルに

この方法では、タイトルのリンクの擬似要素でカード全体をカバーし、「詳細を見る」は視覚的な装飾として<span>にします。

「詳細を見る」を<a>のままtabindex="-1"aria-hidden="true" にしても、スクリーンリーダーのリンクリストや、要素移動モードでノイズになるので、<span>にするのがいいと考えます。

<article class="article-card" aria-labelledby="article-title">
  <img src="thumbnail.jpg" alt="">
  <h3 id="article-title"><a href="#" class="card-link">記事タイトル</a></h3>
  <p>記事の概要...</p>
  <span class="card-detail-link">詳細を見る</span>
</article>
.article-card {
  position: relative;
}

.card-link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

.card-link:focus-visible {
  outline: none;
}

.card-link:focus-visible::after {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* カード内に複数のリンクがある場合の例 */
.article-card a:not(.card-link) {
  position: relative;
  z-index: 2;
}

メリット:

  • セマンティックな構造を保てる
  • スクリーンリーダーで自然に読み上げられる
  • カード内に複数のリンクを配置できる(カテゴリ、タグ、著者リンクなど)

デメリット:

  • z-indexの管理が必要(ただし、一度設定すれば問題ない)

パターン4: カード全体を<a>で囲む

この方法では、カード全体が一つのリンクになるため、「詳細を見る」は自然に<span>になります。

<article class="article-card" aria-labelledby="article-title">
  <a href="#" class="card-link">
    <img src="thumbnail.jpg" alt="">
    <h3 id="article-title">記事タイトル</h3>
    <p>記事の概要...</p>
    <span class="card-detail-link">詳細を見る</span>
  </a>
</article>

メリット:

  • 実装がシンプル
  • CSSの調整が容易

デメリット:

  • スクリーンリーダーによっては全テキストが連結して読み上げられる場合がある (特にVoiceOverでは「記事タイトル記事の概要...詳細を見る、リンク」となる)
  • カード内に複数のリンクを配置できない

各パターンのサンプル

まとめ

アクセシブルなカード型コンポーネントの実装には、複数のアプローチが存在します。重要なのは、「これが唯一の正解」という実装パターンは存在せず、状況によって最適な解が変わるということです。

実装にあたっては以下を意識しておくことが重要です。

  1. 実際に使う人が困らない実装を選ぶ
  2. 画像の意味、カードの用途、サイト全体の構成を考慮する
  3. 実用的で保守しやすい実装を優先する

この記事を書いた人

DTPからWebの世界へ飛び込み、気づけばマークアップもフロントエンドもディレクションもアクセシビリティもこなす"技の仙人"。リベロジック創業期からマルチに活躍し、今や社内の生き字引的存在。最近は「アクセシビリティ対応、もっとAIに頼れないかな?」と、プロンプトを駆使した効率化の探究にハマり中。技術も思考も、まだまだ進化中

フタさん

IAAP認定ウェブアクセシビリティスペシャリスト(WAS) / マークアップエンジニア / フロントエンドエンジニア / ウェブディレクター

このスタッフの記事を見る

安心のチーム体制とスピードのある対応力が自慢

リベロジックでは、ベテランスタッフが積極的にプロジェクトを推進するため、お客様から高く評価されています。
プロジェクトマネージャー、ディレクターをきちんとアサインし、プロジェクト全体をスムーズに進行することを心掛けています。 不必要なフルコミットでのコスト増加を防ぎ、適材適所にリソースを配分するスタイルで、業務内容の把握から見積作成/提出の速さにも定評があります。

当社はSES的な常駐業務等は積極的に行っておりませんので予めご了承ください。

Slack、Teams、Redmine、Backlog、Asana、Jira、Notion、Google Workspace、Zoom、Webexなど、ほぼすべての主要なプロジェクト管理ツールやチャットツールをご利用いただけます。

ウェブアクセシビリティ対応でお困りなことはございませんか?

ケーススタディ