# ページによって順序や名前が変わるナビゲーション

Source: https://easeweb.dev/learn/consistent-navigation
Topics: メニューとナビゲーション > ナビゲーションと操作要素がページ間で一貫している (WCAG 3.2.3, 3.2.4)
The fix: ブログも含め、すべてのページのヘッダーとフッターを1つの共通のリンクの一覧から作り、どこでもリンクが同じ順序、同じ名前になるようにします。ページごとにリンクを足したり省いたりすることはできます。
Test with: screen reader, keyboard, zoom
References: https://www.w3.org/WAI/WCAG22/Understanding/consistent-navigation.html https://www.w3.org/WAI/WCAG22/Understanding/consistent-identification.html https://www.w3.org/WAI/WCAG22/Techniques/general/G61 https://www.w3.org/WAI/WCAG22/Techniques/failures/F66 https://www.w3.org/WAI/WCAG22/Techniques/failures/F31

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

## 場面

ある生活雑貨のショップのページは、共通のヘッダーを使っています。ロゴ、Shop、Sale、Journal、Aboutのメニュー、そしてAccountとBasketです。レシピや読み物を載せるJournalは別のブログサービスで動いていて、ヘッダーはブログを作ったときにショップのものを写しました。それ以来、どちらも別々に手直しされてきました。Journalでは「Journalのページだから」とメニューの先頭がJournalになり、同じページへ行く買い物かごのリンクはCartと書かれています。ショップでメニューを使っていた人がJournalの記事へ移ると、リンクの順序が違い、Basketが見当たりません。

同じずれは、ほかの形でも起きます。

- メニューを人気順やページの内容に合わせて並べ替えるため、同じリンクがページによって違う順序になる。
- 検索ボタンが、ほとんどのページでは「検索」、検索結果のページでは「Go」になっている。
- アイコンのボタンの名前が、ほとんどのページとほかのチームが作ったページで違う。たとえば「メニューを開く」と「ナビゲーション」。

## 確認できる問題

レベルAAの2つの達成基準が、これを扱います。3.2.3「一貫したナビゲーション」は、複数のページで繰り返されるナビゲーションは、利用者が変えた場合を除き、毎回同じ相対的な順序で現れることを求めています。3.2.4「一貫した識別性」は、複数のページで同じ働きをする部品は一貫して識別されることを求めています。同じ働きなら、同じ名前です。

同じ相対的な順序は、まったく同じという意味ではありません。Journalのカテゴリーのようにリンクを足したり、今いるページへのリンクのように省いたりしても、ほかのページと共通するリンクが同じ順序なら適合します。この例では、共通する2つのリンクが入れ替わっています。ショップのページではJournalがSaleの後にあり、JournalのページではShopの前にあります。これは失敗例F66に当たります。

一貫していることも、まったく同じという意味ではありません。商品を入れた後の「Basket (2)」は、やはりBasketです。しかし、BasketとCartは1つのリンクの2つの名前で、失敗例F31に当たります。同じものだと分からない人もいます。ページ群を決めるのは、共通の目的と、同じ作成者や組織が作っていることで、ページを出すサービスではありません。Journalはショップ自身のもので、ショップのアドレスにあり、ショップのヘッダーの写しを使っているため、同じページ群に入ります。

## 利用者への影響

いちばん違いが出やすいのは、ブログ、ヘルプセンター、店舗検索など、よそで作られ、それぞれがヘッダーの写しを持つページです。

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

どのページのメニューも単独では問題がなく、axeなどの自動チェックは1ページずつ調べます。3.2.3と3.2.4を扱うルールはありません。EaseWebの診断は、一回の実行で調べたページどうしを比べます。ヘッダー、ナビゲーションメニュー、フッターで繰り返される2つのリンクが、一部のページと別のページで逆の順序になっている場合と、同じアドレスへのリンクの名前が、多くのページでの名前と1語も共通しない場合を報告します。実行で開かなかったページや mainランドマークがちょうど1つではないページのリンク、同じ働きを別の名前で持つボタン、CSSだけで起きる変化は見分けられません。渡されたページしか比べないため、Journalも対象に含める必要があります。AIのコードアシスタントに「ブログにヘッダーを付けて」と頼むと、見たものから新しいヘッダーを書き、独自の順序と言葉にしてしまうことがあります。

## 修正前：Journal独自のヘッダーの写し

```html shop.html
<!-- Every shop page -->
<header class="site-header">
  <a href="/" class="logo">Fernhill</a>
  <nav aria-label="Main">
    <a href="/shop">Shop</a>
    <a href="/sale">Sale</a>
    <a href="/journal">Journal</a>
    <a href="/about">About</a>
  </nav>
  <a href="/account">Account</a>
  <a href="/basket">Basket</a>
</header>
```

```html journal.html
<!-- Every Journal page, from the blog platform's own template -->
<header class="blog-header">
  <a href="/" class="logo">Fernhill</a>
  <nav aria-label="Main">
    <a href="/journal">Journal</a>
    <a href="/shop">Shop</a>
    <a href="/sale">Sale</a>
    <a href="/about">About</a>
  </nav>
  <a href="/account">Account</a>
  <a href="/basket">Cart</a>
</header>
```

2つのヘッダーには同じリンクがありますが、Journalはメニューの先頭に移り、買い物かごへのリンクはCartと呼ばれています。どちらのヘッダーも単独では正しく、並べると両方の基準を満たしません。

## 修正後：どのページでも1つのリンクの一覧から作るヘッダー

```js nav.js
// The site's header links, in order. The shop and the Journal both render this list.
export const MAIN_NAV = [
  { href: '/shop', label: 'Shop' },
  { href: '/sale', label: 'Sale' },
  { href: '/journal', label: 'Journal' },
  { href: '/about', label: 'About' }
];
export const ACCOUNT_NAV = [
  { href: '/account', label: 'Account' },
  { href: '/basket', label: 'Basket' }
];
```

```html header.html
<!-- What the shared header renders on every page, the Journal's included -->
<header class="site-header">
  <a href="/" class="logo">Fernhill</a>
  <nav aria-label="Main">
    <a href="/shop">Shop</a>
    <a href="/sale">Sale</a>
    <a href="/journal" aria-current="page">Journal</a>
    <a href="/about">About</a>
  </nav>
  <a href="/account">Account</a>
  <a href="/basket">Basket</a>
</header>
```

どちらのサービスも同じ2つの一覧からヘッダーを作るため、Journalだけが自分のリンクを先頭に置いたり、買い物かごのリンクを別の名前で呼んだりするには、すべてのページを変えることになります。Journalのページでは、Journalのリンクが現在のページとして示されます。見た目や読み上げは変わり得ますが、位置は変わりません。示し方は[現在のページを見た目だけで示すナビゲーション](/ja/learn/current-page)で説明しています。カテゴリーの並びなど、Journalにさらに必要なものがあれば、共通のメニューの後に足します。リンクを足しても、共通するリンクの順序は保たれます。

## 実装の判断

ブログが共通のヘッダーをどう受け取るかは、サービスによって違います。

- ショップ自身のコードが表示するブログ：ほかのすべてのページと同じく、ショップのヘッダーのコンポーネントを使う。
- 独自のテンプレートを持つブログサービス：写しを手直しするのではなく、ビルド時に同じ一覧からヘッダーを生成するか、ショップが公開するファイルから一覧を読み込ませる。
- ヘルプセンターなど、HTMLしか受け付けない外部のサービス：ショップが出力したヘッダーを貼り付け、一覧が変わるたびに貼り直す。写しをそろえ続ける仕組みがないため、3つの中でいちばん弱い方法です。メニューを変えるたびに確認してください。

順序は固定します。人気順、今週のセール、ページの属するセクションで並べ替えるメニューは、リンクがすべて同じでも、ページによって順序が変わります。変わるリンクは、繰り返されるメニューの外の、別の場所にまとめてください。

名前も、アイコンのボタンのアクセシブルな名前も、どのテンプレートでもそろえます。「Basket (2)」のように件数を加えるのは問題ありません。名前が何であるかを言い続けているからです。違う言葉は、書いた人には同じ意味でも問題です。1つを選び、フッターやスマートフォンのメニューも含めて、どこでもそれを使ってください。

スマートフォンでは、メニューがメニューボタンの中に入ることがよくあります。これは別のレイアウトなので、同じ幅のページどうしで比べます。ただし、その幅でもどのページでもリンクの順序と名前をそろえる必要があります。

一部のページだけ、CSSの `order`、`flex-direction: row-reverse`、グリッドの配置でメニューを並べ替えないでください。スクリーンリーダーとキーボードはソースの順序に従うため、見た目はそろっていても読まれる順序はそろわず、その逆も起きます。

ヘルプのリンクや連絡先も同じで、3.2.6はそれを同じ場所に置くことを求めています。[ページごとに場所が変わるヘルプリンク](/ja/learn/consistent-help)を参照してください。

## 修正の確認

1. トップページ、商品ページ、Journalの記事、カート、エラーページから、ヘッダー、ナビゲーションメニュー、フッターで繰り返されるリンクを挙げる。
2. 繰り返されるリンクの組ごとに、両方を持つどのページでも同じ順序か、画面上だけでなくソースでも確認する。
3. 繰り返されるリンクとボタンごとに、件数や状態を除いてどのページでも同じ名前か、見える文字とスクリーンリーダーの読み上げの両方で確認する。
4. ほかのサービスが出すページを特に確認する。ブログ、ヘルプセンター、店舗検索。
5. スクリーンリーダーでそれぞれのページのリンクの一覧を出し、繰り返されるリンクが同じ順序、同じ名前で並ぶか確認する。

OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。メニュー、テンプレート、サイトが使うサービスを変更した際は、再度確認します。

## 制限

このサンプルは、どのサイトでも同じ結果になることを保証するものではありません。この基準が求めるのは一貫性で、メニューのよさではありません。どこでも同じリンクでも、分かりにくいことはあります。対象は一つのページ群なので、別の人たちが書き、ナビゲーションも異なるサブドメインのブログのように、それ自体が別のページ群になるサイトは、一貫していれば独自のメニューを持てます。リーダー表示や、設定で並べ替えたメニューのように、利用者自身が起こす変化は認められています。サイト全体を、ページの種類ごとに、利用者が頼る人や道具と一緒に確認してください。

---

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