パンくずリスト
「ホーム › カテゴリ › … › 現在地」と階層をたどれるパンくず。最後の項目は現在地として aria-current で示し、リンクにはしない。
プレビュー
操作動きのない質感・レイアウトの見本です。
最後の項目だけ <a> ではなく aria-current="page" を付けた <span> にし、現在地はリンクにしないのが定石です。区切りの › は装飾なので各 <li class="bc-sep"> に aria-hidden="true" を付け、読み上げ時に読まれないようにしています。項目が多いときは中間を「…」に畳んでも構いません。
使いどころ
商品ページ・記事ページなど、サイト内の階層が3段以上あるコンテンツで『今どの階層にいるか』と『一段上の階層へすぐ戻れる』の両方を満たしたい場面に向く。検索エンジンから直接階層の深いページへ着地したユーザーにとって、パンくずはその場でサイト構造を把握できる数少ない手がかりになる。逆に、階層が1〜2段しかないサイトや、常時表示されるサイドバーナビ・タブバーで既に現在地が示されている画面では、同じ情報を二重に出すだけの冗長な要素になりやすい。このパーツはJavaScriptを一切使わない静的なマークアップだけで完結しており、階層の深さに応じてbc-listの中身をサーバー側またはビルド時に生成する運用が前提になっている。
仕組み
実装はol要素とflexboxだけの静的なリストで、JavaScriptは使っていない。各階層はli.bc-itemの中のa.bc-linkで、区切り記号(›)はli.bc-sepとして別のliに独立させている。区切りをa要素の中や::afterに埋め込まず独立したliにしているのは、リンクとテキストを完全に分離してマークアップを単純にするための設計判断で、視覚的な整列は.bc-listのdisplay:flex; flex-wrap:wrap; gapで吸収している。最後の階層(現在地)だけはa要素ではなくspan.bc-currentにし、aria-current="page"を付けている。これは現在地はリンクとして機能させる意味がないという定石に沿った判断で、視覚的にも太字(font-weight:700)にしてリンクと区別している。flex-wrap:wrapにより、長い階層名が並んでも折り返して2行以上になり、横スクロールは発生しない構造になっている。
実装の注意
このマークアップには、階層が非常に深くなったとき(6段、7段など)に中間の階層を「…」へ畳む仕組みが用意されていない。noteでは『項目が多いときは中間を「…」に畳んでも構いません』と方針だけ示されているが、実装(ellipsis化・クリックで展開する処理など)はこのパーツに含まれておらず、深い階層を扱うサイトでは別途paginationのような省略ロジックを自前で組む必要がある。またflex-wrap:wrapによる折り返しは横幅を圧迫しないための工夫だが、極端に長い階層名が単体で.bc-list全体の横幅を超える場合、その1項目だけが折り返されずにコンテナからはみ出す可能性があるため、white-space:nowrapを外すか、max-widthとtext-overflow:ellipsisを個別のbc-linkに足す対処が要る。JSを持たないため、階層データを動的に組み替える(元になるURL階層の解析など)処理はこのパーツの外側で行う前提になっている。
アクセシビリティ
navをaria-label="パンくずリスト"で囲み、リスト構造(ol)を使い、現在地をaria-current="page"のspanにする、という基本パターンは正しく実装されている。区切りの›アイコンは情報を持たない装飾なので、各li.bc-sepにaria-hidden="true"を付けて読み上げ対象から除外しているのも適切。加えて、ホームへのリンクにはアイコンSVGとテキスト『ホーム』を両方入れているため、アイコンだけのリンクにありがちな『読み上げても意味が分からない』問題も起きていない。ol要素自体にラベルは無く、nav側のaria-labelだけで『これはパンくずのリストである』ことを伝えている構成だが、これはWAI-ARIAの標準的な実装として妥当な範囲。改善の余地があるとすれば、階層が深くなったときの省略(…)機能を足す場合、省略部分をボタン化してaria-label="中間の階層を表示"のような説明を付ける配慮が要ることくらいで、現状の3〜4階層程度の使い方では大きな不足はない。
調整して使う
区切り記号は›のほかに/(スラッシュ)や>のようなテキスト文字に変えることもでき、その場合はSVGではなくCSSの::beforeで疑似要素として置く実装に切り替えると、アイコンの読み込みを省ける。ホームだけアイコン付き・以降はテキストのみという構成をデモは採用しているが、全階層をテキストのみに統一するとよりシンプルになる。深い階層を扱うサイトでは、先頭のホームと直近2階層だけを表示し、間を『…』ボタンでクリックすると展開する省略機能を追加するのが実務では定番の拡張になる。モバイル幅では横幅の制約が厳しいため、直近1階層だけを『‹ 一つ上のカテゴリへ』という戻るリンク的な簡易表示に切り替えるレスポンシブ対応も選択肢に入る。
コード(コピーして使えます)
<nav class="bc" aria-label="パンくずリスト">
<ol class="bc-list">
<li class="bc-item">
<a class="bc-link" href="#">
<svg class="bc-home" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5"/></svg>
ホーム
</a>
</li>
<li class="bc-sep" aria-hidden="true">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><polyline points="4,2 8,6 4,10" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</li>
<li class="bc-item"><a class="bc-link" href="#">レディース</a></li>
<li class="bc-sep" aria-hidden="true">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><polyline points="4,2 8,6 4,10" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</li>
<li class="bc-item"><a class="bc-link" href="#">バッグ</a></li>
<li class="bc-sep" aria-hidden="true">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><polyline points="4,2 8,6 4,10" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</li>
<li class="bc-item"><span class="bc-current" aria-current="page">トートバッグ</span></li>
</ol>
</nav>