# どれも同じ「続きを読む」のリンク

Source: https://easeweb.dev/learn/read-more
Topics: ボタンとリンク > 「続きを読む」リンクが行き先を伝える (WCAG 2.4.4, 2.5.3)
The fix: 各カードのリンクに、リンク先が分かり、表示している言葉で始まる名前を付けます。「続きを読む」の後ろに記事のタイトルを視覚的に隠したテキストで足すか、タイトル自体をリンクにして「続きを読む」をなくすか、「続きを読む」をリンク先が分かる見える言葉に置き換えます。
Test with: screen reader, speech input, keyboard, mouse
References: https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html https://www.w3.org/WAI/WCAG22/Techniques/failures/F63 https://www.w3.org/WAI/WCAG22/Techniques/css/C7 https://www.w3.org/WAI/WCAG22/Techniques/html/H80 https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-link-only.html https://ictbaseline.access-board.gov/web-baselines/14Links

よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。

## 場面

生活雑貨のショップの読み物ページが、新しい記事3本をカードで並べています。各カードには写真、太字のタイトル、記事の一文、矢印付きの緑の「続きを読む」リンクがあります。どのカードも同じリンクで終わるため、並びがそろい、入口がいつも同じ場所に見えます。スクリーンリーダーの利用者がリンク一覧を開いて記事を選ぼうとすると、「続きを読む、続きを読む、続きを読む」と聞こえます。どれがトラベルマグの記事かを示すものがないため、一つずつ開いて確かめることになります。

リンクがどれも同じに聞こえると指摘された開発者は、それぞれに記事のタイトルを入れた `aria-label` を付けます。リンク一覧は「ホーローマグのお手入れ」「ストーンウェアが冷めにくい理由」「トラベルマグの選び方」と分かりやすくなります。ところが音声操作の利用者がカードを見て「続きを読むをクリック」と話しても、何も起きません。その名前のリンクが、もうページにないからです。

## 確認できる問題

WCAG 2.4.4「リンクの目的（コンテキスト内）」は、リンクの目的を、テキストと、プログラムで判別できるリンクの文脈とを合わせて分かるようにすることを認めています。文脈とは、同じ文、段落、リスト項目、表のセルにあるテキスト、そのセルの表の見出し、ARIAでリンクに結び付けた言葉です。このカードでは、タイトルは独立した段落で、リンクはその後の普通の `div` の中にあります。コード上、タイトルはリンクの文脈ではありません。W3Cは、説明の段落の次の段落に置いた「Read More」リンクを、まさにこの失敗例F63として挙げています。Tabで移動したときやリンク一覧のように単独で読まれると、「続きを読む」はリンク先について何も伝えません。

カードの作り方によって答えは変わります。カードがリスト項目なら、タイトルはリンクと同じリスト項目にあり（達成方法H77）、リンクは2.4.4を満たす可能性が高いです。リンクの前に本物の見出しがある場合は、それより弱い根拠です。W3Cは、リンクを直前の見出しと合わせて読む方法を参考の達成方法（H80）としてしか挙げておらず、リンクの文脈の定義にも、米国のSection 508のベースラインテストにも、見出しは含まれていません。それでも見出しを文脈と認める評価者もいます。どの場合も、リンク一覧には同じ項目が3つ並んだままで、レベルAAAの2.4.9「リンクの目的（リンクのみ）」は満たしません。

手早い修正は、一つの問題を別の問題に取り替えます。`aria-label` はリンクのテキストに代わって名前になるため、各リンクはリンク先を伝え、2.4.4は満たします。しかし画面の言葉「続きを読む」は名前に含まれなくなります。WCAG 2.5.3「ラベルを含む名前」（レベルA）は、見える言葉がある操作要素の名前に、その言葉が含まれることを求めています。見えている言葉を話して操作できるようにするためです。この問題は[表示と名前が食い違うボタンとリンク](/ja/learn/label-in-name)で詳しく扱っています。

## 利用者への影響

カードが並ぶところなら、どこでも起きます。ブログやニュースの一覧、商品の紹介、検索結果、ヘルプセンターのタイルなどです。「詳しくはこちら」「今すぐ購入」「詳細」「こちら」も同じように問題になります。

## 自動チェックとAIの限界

axe の `link-name` ルールは、テキストがあるため「続きを読む」をすべて合格にします。リンクの周りの言葉がリンク先を示しているかは判断が必要なため、この診断では「続きを読む」「詳しくはこちら」「Learn more」のような汎用的な名前のリンクをすべて要確認項目として記録します。スクリーンリーダーがたどれる段落、リスト項目、表のセル、説明、見出しと、同じ名前で別の場所へ向かうリンクの数を添えます。ANDIも、名前が同じでアドレスが違うリンクに独自の警告を出します。そのうえで、人か診断のAIレビューが、文脈がリンク先を示しているかを判断します。2つ目の修正前の例は、診断で実行し要確認項目として報告している axe の試験的なルール `label-content-name-mismatch` が、aria-label を表示テキストと比べて検出します。「名前が同じリンク」を直すよう頼まれたAIのコーディングツールは、2つ目の修正前の例をそのまま書くことがあります。

## 修正前：どのカードにも同じ「続きを読む」

```html
<div class="cards">
  <div class="card">
    <img src="/images/journal/enamel-mug.jpg" alt="">
    <p class="card-title">ホーローマグのお手入れ</p>
    <p>柔らかいスポンジを使い、磨き粉を避ければ、つやが長持ちします。</p>
    <a href="/journal/enamel-care" class="card-more">続きを読む</a>
  </div>
  …
</div>
```

```css
.card-title {
  font-size: 1.125rem;
  font-weight: 700;
}
```

タイトルは見出しのように見えても段落で、リンクはどちらの段落にも入っていません。そのため、コード上「続きを読む」とその記事を結び付けるものがありません。2.4.4を満たさず、どのカードのリンクもリンク一覧では同じ項目になります。

## 修正前：画面の言葉を外した aria-label

```html
<div class="cards">
  <div class="card">
    <img src="/images/journal/enamel-mug.jpg" alt="">
    <p class="card-title">ホーローマグのお手入れ</p>
    <p>柔らかいスポンジを使い、磨き粉を避ければ、つやが長持ちします。</p>
    <a href="/journal/enamel-care" class="card-more" aria-label="ホーローマグのお手入れ">続きを読む</a>
  </div>
  …
</div>
```

```css
.card-title {
  font-size: 1.125rem;
  font-weight: 700;
}
```

`aria-label` が名前になるため、リンクはリンク先を伝え、2.4.4を満たします。しかし名前に表示の言葉「続きを読む」が含まれないため2.5.3を満たさず、「続きを読むをクリック」と話しても何も見つかりません。

## 修正後：「続きを読む」の後ろに隠した言葉

```html
<div class="cards">
  <div class="card">
    <img src="/images/journal/enamel-mug.jpg" alt="">
    <p class="card-title">ホーローマグのお手入れ</p>
    <p>柔らかいスポンジを使い、磨き粉を避ければ、つやが長持ちします。</p>
    <a href="/journal/enamel-care" class="card-more">
      続きを読む<span class="visually-hidden">：ホーローマグのお手入れ</span>
    </a>
  </div>
  …
</div>
```

```css
.card-title {
  font-size: 1.125rem;
  font-weight: 700;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
```

最も小さな変更で、デザインは描いたとおりに残ります。リンクの名前は「続きを読む：ホーローマグのお手入れ」になります。リンク一覧でもリンク先が分かるため2.4.4と2.4.9を満たし（達成方法C7）、画面の言葉で始まるため2.5.3も満たします。「続きを読むをクリック」は3枚のカードすべてに一致し、同じラベルが並ぶときと同じように、Dragonなどの音声操作が番号を振って選ばせます。リンク自身の `id` を先に、タイトルの `id` を後に並べた `aria-labelledby="more-enamel title-enamel"` でも、span なしで近い名前「続きを読む ホーローマグのお手入れ」になります。代わりにカードごとに `id` が2つ要ります。

## 修正後：タイトルをリンクにする

```html
<div class="cards">
  <div class="card">
    <img src="/images/journal/enamel-mug.jpg" alt="">
    <h3 class="card-title">
      <a href="/journal/enamel-care" class="card-link">ホーローマグのお手入れ</a>
    </h3>
    <p>柔らかいスポンジを使い、磨き粉を避ければ、つやが長持ちします。</p>
  </div>
  …
</div>
```

```css
.card-title {
  font-size: 1.125rem;
  font-weight: 700;
}

/* タイトルのリンクをカード全体に広げます。 */
.card {
  position: relative;
}

.card-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

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

.card-link:focus-visible::after {
  outline: 3px solid var(--focus-ring);
  outline-offset: -3px;
}
```

「続きを読む」はなくなり、誰もが読むタイトルがカードで唯一のリンクになります。名前はタイトルなので、リンク一覧は「ホーローマグのお手入れ」と読み、音声操作の利用者は見えているタイトルを話せます。2.4.4、2.4.9、2.5.3を満たし、タイトルが見出しにもなるため、スクリーンリーダー利用者は見出しでカードからカードへ移動できます。疑似要素は、リンクのクリック範囲をカード全体に広げます。タイトルだけをクリックできればよいなら、なくして構いません。カード内に「保存」ボタンやタグのような別のリンクやボタンがある場合は、`position: relative` と疑似要素より上の `z-index` を指定しないと押せません。

## 修正後：リンク先が分かる言葉にする

```html
<div class="cards">
  <div class="card">
    <img src="/images/journal/enamel-mug.jpg" alt="">
    <p class="card-title">ホーローマグのお手入れ</p>
    <p>柔らかいスポンジを使い、磨き粉を避ければ、つやが長持ちします。</p>
    <a href="/journal/enamel-care" class="card-more">お手入れ方法を読む</a>
  </div>
  …
</div>
```

```css
.card-title {
  font-size: 1.125rem;
  font-weight: 700;
}
```

各カードのリンクに、それぞれの見える言葉を付けます。「お手入れ方法を読む」「ストーンウェアの記事を読む」「トラベルマグを比べる」などです。名前は表示テキストそのものなので、隠したテキストも合わせておくものもなく、2.4.4、2.4.9、2.5.3を満たします。言葉はスクリーンリーダー利用者だけでなく、流し読みするすべての人に役立ちます。見た目は変わります。リンクは同じラベルの繰り返しではなくなり、長さもそろわないため、並びの均一さは減ります。また、カードごとに誰かがリンクの言葉を書く必要があります。

## どの方法を選ぶか

3つとも2.4.4と2.5.3を満たし、2.4.9が求めるとおり、リンクだけで意味が分かるようになります。隠した言葉は画面を何も変えないため、「続きを読む」を残すデザインや、追加しかできないテーマに向いています。ただし「続きを読むをクリック」はすべてのカードに一致し、Appleの音声コントロールは名前全体が必要だと報告されているため、MacやiPhoneでは番号に頼ることになるかもしれません。タイトルをリンクにする方法は最も整ったマークアップで、カードごとに一つのリンクが、誰もが見る言葉で名付けられます。タイトルだけで内容が十分伝わるカードに向いていますが、広げたクリック範囲にはカード内の他の操作要素への配慮が要ります。見える言葉にする方法は、カードごとに行動を促す言葉を置きたいデザインに向き、カードごとに書き手が必要です。どのサイトにも当てはまる一つの正解はないため、デザインで何を残したいかで選びます。

## 実装の判断

**aria-labelではなく隠したテキスト。** `aria-label` を使う場合は、「続きを読む：ホーローマグのお手入れ」のように表示の言葉で始めます。それでも隠したテキストの方が適しています。隠したテキストはページと一緒に翻訳されますが、`aria-label` はブラウザーの翻訳機能によっては元の言語のまま残り、食い違いが戻ります。隠すときは clip を使った `.visually-hidden` クラスを使い、名前からも言葉を消してしまう `display: none` は使いません。

**aria-describedbyではリンク一覧は直らない。** `aria-describedby` でタイトルを指すと、タイトルは説明として「続きを読む、リンク」の後に読まれます。W3Cの失敗例のテストもSection 508のテストも説明を数に入れるため、リンクは2.4.4を満たす可能性が高いですが、スクリーンリーダーのリンク一覧は名前しか表示せず、「続きを読む」が3回続いたままです。

**見出しリンクの横に隠した「続きを読む」。** よくある形に、見える「続きを読む」を残したまま、あらゆるものから外すものがあります。`aria-hidden="true"` でスクリーンリーダーに読ませず、`tabindex="-1"` でTabでも飛ばし、本当のリンクはタイトルにします。スクリーンリーダーにはカードごとに一つのリンクしか聞こえませんが、きれいな修正ではありません。見えている言葉どおり「続きを読むをクリック」と話した音声操作の利用者には何も起きません。アクセシビリティツリーをもとに動く音声認識ソフトは、隠したリンクを見つけられないからです。目の見えるキーボード利用者には、Tabで決して届かないリンクが見えます。隠すなら全員から隠し、隠さないなら誰からも隠さないようにします。言葉を残したいなら、隠した言葉の修正のように、その言葉をリンクの名前に入れます。

**カード全体を一つのリンクで囲む。** カード全体を一つの `<a>` で囲むのはHTMLとして正しいですが、カード内のすべての文字がリンクの名前になり、スクリーンリーダーは長い文章を読み上げます。カード内に別のリンクやボタンも置けません。タイトルのリンクを広げれば、どちらも避けられます。

**カードのタイトルはたいてい見出し。** 周りの文字より大きく太く描いたタイトルは見出しとして読まれ、スクリーンリーダー利用者は見出しで移動します。タイトルをリンクにする修正のように、ページに合った階層の見出しにすると、どの修正を選んでも役立ちます。[大きさで選ばれ、構造と合わない見出し](/ja/learn/heading-structure)を参照してください。

**汎用的なラベルはどれも同じ問題。** カードに繰り返す「詳しくはこちら」「今すぐ購入」「詳細」「こちら」「見る」も、同じように問題になり、同じ方法で直せます。CMSやデザインシステムでは、カードのコンポーネントにリンクの言葉、または「続きを読む」の後ろに隠す言葉の入力欄を設け、編集者が空欄のままにしたときは記事のタイトルを入れるようにします。そうすれば、むき出しの「続きを読む」のまま新しいカードが公開されることはありません。

**その場で文章を開く「続きを読む」はボタン。** 別のページへ移らず、同じページでレビューや説明の残りを表示する「続きを読む」は `button` です。`href="#"` のリンクにはせず、`aria-expanded` で開いているかどうかを伝えます。1ページに複数あるときは、同じように項目ごとに名前を付けます。ボタンそのものは[開いているか伝わらない表示・非表示ボタン](/ja/learn/show-hide-buttons)で扱っています。

## 修正の確認

1. スクリーンリーダーのリンク一覧（VoiceOverのローター、NVDAとJAWSではInsert + F7）を開き、各カードのリンクでどの記事へ進むかが分かり、他と区別できることを確認する。
2. ブラウザーのアクセシビリティツリーで各カードのリンクを確認し、名前が表示されている言葉を含み、その言葉で始まることを確認する。
3. 音声操作で「クリック」とカードのリンクに表示された言葉を話し、そのリンクへ進むか、同じ言葉のリンクに番号が表示され、どれかを選ぶとそのリンクへ進むことを確認する。
4. 200%の拡大表示とタッチ操作も含め、デザイン上クリックできる場所で各カードを押してリンクが動くこと、カード内の他の操作要素も押せることを確認する。

OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。共通のカードのコンポーネントやテンプレートを変更した際は、再度確認します。

## 制限

このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。コード内のパスとクラス名は仮のものです。音声認識ソフトによって、話した言葉の照合方法は異なるため、利用者が使う音声操作で確認してください。編集者が後からあいまいなリンクのカードを公開することもあるため、公開前の確認にリンクテキストを含めてください。空のリンクでクリックできるようにしたバナーは、[名前のないバナーや画像のリンク](/ja/learn/empty-links)で扱っています。実際に使用する支援技術で、操作全体を確認してください。

---

このガイドをコーディングエージェントで使う: MCP https://easeweb.dev/mcp（設定は https://easeweb.dev/ja/services/developers）
