HTMLでパンくずリストを実装する方法|構造化データ対応


はじめに

前回の記事ではHTMLのセマンティックタグ完全ガイドとしてheader・main・article・sectionの使い分け・nav・aside・footerの役割・スクリーンリーダーへの影響とアクセシビリティ対応を解説しました。今回はHTMLでパンくずリストを実装する方法を解説します。パンくずリストはユーザーが「今どこにいるか」を示すナビゲーションで、ECサイト・ブログ・コーポレートサイトなど幅広い場面で使われます。HTML・CSS・構造化データ(JSON-LD)まで一通り実装できるよう丁寧に解説します。


1. パンくずリストとは

1.1 パンくずリストの役割

パンくずリストの役割:

① ユーザーへの現在地の提示
   → 「ホーム > ブログ > カテゴリー > 記事タイトル」
   → 今自分がサイトのどこにいるかが一目でわかる

② 上位階層への素早い移動
   → 1クリックで上の階層に戻れる
   → ブラウザの「戻る」ボタンより直感的

③ SEOへの貢献
   → 検索エンジンがサイト構造を理解しやすくなる
   → 検索結果にパンくずリストが表示される
     (リッチリザルト)

④ 内部リンクの強化
   → 上位ページへのリンクが増える
   → サイト全体のクローラビリティが上がる

使う場面:
→ 階層が2階層以上あるサイト
→ ブログ・ECサイト・コーポレートサイト
→ カテゴリーが複数あるサイト

使わない場面:
→ 1ページ完結のLP
→ 階層がほとんどないシンプルなサイト

1.2 パンくずリストの種類

パンくずリストの種類:

① 階層型(最も一般的)
   ホーム > カテゴリー > 記事タイトル
   → 現在のページまでの階層を表示する

② 属性型
   ホーム > 色:赤 > サイズ:M > 商品名
   → ECサイトの絞り込み条件を表示する

③ 履歴型(非推奨)
   前のページ > 現在のページ
   → ブラウザの履歴に依存するため
     ユーザーによって表示が変わる
   → SEOにも効果がないため使わない

→ 副業・フリーランス案件では
  ①の階層型を使うことがほとんど

2. HTMLでパンくずリストを実装する

2.1 基本的な実装

<!--
    パンくずリストの実装ポイント:

    ① <nav> タグで囲む
       → aria-label="パンくずリスト" で
         他のnavと区別する

    ② <ol>(順序付きリスト)を使う
       → 順番に意味があるので ol が適切
       → ul(順序なし)は不適切

    ③ 現在のページには aria-current="page" を付ける
       → スクリーンリーダーに
         「現在のページ」と伝える

    ④ 現在のページにはリンクを付けない
       → 今いるページにリンクする必要はない
-->

<nav aria-label="パンくずリスト">
    <ol class="breadcrumb">
        <li class="breadcrumb__item">
            <a href="/">ホーム</a>
        </li>
        <li class="breadcrumb__item">
            <a href="/blog/">ブログ</a>
        </li>
        <li class="breadcrumb__item">
            <a href="/blog/html/">HTML</a>
        </li>
        <li class="breadcrumb__item" aria-current="page">
            パンくずリストの実装方法
            <!-- 現在のページはリンクなし -->
        </li>
    </ol>
</nav>

2.2 WordPressでの実装

<?php
/*
    WordPressでパンくずリストを実装する

    方法①:手動で実装する(シンプルな場合)
    方法②:Yoast SEOプラグインの関数を使う(推奨)
*/

// 方法①:手動実装(functions.php に追加する)
function custom_breadcrumb() {
    // ホームページでは表示しない
    if ( is_front_page() ) {
        return;
    }

    echo '<nav aria-label="パンくずリスト">';
    echo '<ol class="breadcrumb">';

    // ホーム
    echo '<li class="breadcrumb__item">';
    echo '<a href="' . home_url() . '">ホーム</a>';
    echo '</li>';

    if ( is_category() || is_single() ) {
        // カテゴリーページ・投稿ページ
        $category = get_the_category();
        if ( $category ) {
            echo '<li class="breadcrumb__item">';
            echo '<a href="' . get_category_link( $category[0]->term_id ) . '">';
            echo esc_html( $category[0]->name );
            echo '</a>';
            echo '</li>';
        }
    }

    if ( is_single() || is_page() ) {
        // 投稿・固定ページ(現在のページ)
        echo '<li class="breadcrumb__item" aria-current="page">';
        echo esc_html( get_the_title() );
        echo '</li>';
    } elseif ( is_category() ) {
        // カテゴリーページ(現在のページ)
        echo '<li class="breadcrumb__item" aria-current="page">';
        echo esc_html( single_cat_title( '', false ) );
        echo '</li>';
    }

    echo '</ol>';
    echo '</nav>';
}

// テンプレートファイルで呼び出す
// <?php custom_breadcrumb(); ?>
?>
<?php
// 方法②:Yoast SEOのパンくずリストを使う(推奨)
// Yoast SEO がインストールされている場合

// テンプレートファイル(single.php・page.phpなど)に書く
if ( function_exists( 'yoast_breadcrumb' ) ) {
    yoast_breadcrumb(
        '<nav aria-label="パンくずリスト"><ol class="breadcrumb">',
        '</ol></nav>'
    );
}

/*
    Yoast SEOのパンくずリスト設定:
    管理画面 > SEO > 検索での見え方 > パンくずリスト
    → 「パンくずリストを有効化する」をONにする
    → セパレーター・ホームのテキストなどを設定する
*/
?>

3. CSSでスタイリングする

3.1 基本的なスタイル

/* パンくずリストの基本スタイル */
.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    list-style: none;
    margin: 0;
    padding: 12px 0;
    font-size: 14px;
    color: #666;
}

.breadcrumb__item {
    display: flex;
    align-items: center;
}

/* セパレーター(区切り文字)を疑似要素で表示する */
.breadcrumb__item + .breadcrumb__item::before {
    content: '>';
    /*
        他のセパレーターの例:
        content: '/';
        content: '›';
        content: '»';
        content: '▶';
        content: '—';
    */
    display: inline-block;
    margin: 0 8px;
    color: #999;
    font-size: 12px;
}

/* リンクのスタイル */
.breadcrumb a {
    color: #1A5FC0;
    text-decoration: none;
    transition: color 0.2s ease;
}

.breadcrumb a:hover {
    color: #0D3B8C;
    text-decoration: underline;
}

.breadcrumb a:focus-visible {
    outline: 2px solid #1A5FC0;
    outline-offset: 2px;
    border-radius: 2px;
}

/* 現在のページ(リンクなし) */
.breadcrumb [aria-current="page"] {
    color: #333;
    font-weight: 500;
}

3.2 アイコンを使ったスタイル

/* ホームアイコン付きパンくずリスト */
.breadcrumb__item:first-child a::before {
    content: '';
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-right: 4px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%231A5FC0'%3E%3Cpath d='M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'/%3E%3C/svg%3E");
    background-size: contain;
    background-repeat: no-repeat;
    vertical-align: middle;
}

/* 矢印アイコンをSVGで表示する */
.breadcrumb__item + .breadcrumb__item::before {
    content: '';
    display: inline-block;
    width: 12px;
    height: 12px;
    margin: 0 6px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2'%3E%3Cpolyline points='9 18 15 12 9 6'%3E%3C/polyline%3E%3C/svg%3E");
    background-size: contain;
    background-repeat: no-repeat;
    vertical-align: middle;
}

3.3 長いパンくずリストの対応

/*
    パンくずリストが長い場合の対応:
    スマートフォンでは途中を省略する
*/

/* モバイルでは直前の階層だけを表示する */
@media ( max-width: 768px ) {
    .breadcrumb__item {
        display: none; /* すべて非表示 */
    }

    /* 最後から2番目(直前の階層)だけ表示 */
    .breadcrumb__item:nth-last-child( 2 ) {
        display: flex;
    }

    /* 直前の階層に「←」を付ける */
    .breadcrumb__item:nth-last-child( 2 )::before {
        content: '←';
        margin-right: 4px;
        color: #1A5FC0;
    }

    /* セパレーターは非表示 */
    .breadcrumb__item:nth-last-child( 2 )::after {
        display: none;
    }
}

/* テキストが長い場合は省略する */
.breadcrumb__item {
    max-width: 200px;
}

.breadcrumb a,
.breadcrumb [aria-current="page"] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
    max-width: 100%;
}

4. 構造化データ(JSON-LD)の実装

4.1 構造化データとは

構造化データ(JSON-LD):
→ 検索エンジンがページの内容を
  正確に理解するためのデータ形式

パンくずリストに構造化データを追加すると:
→ 検索結果にパンくずリストが表示される
   (リッチリザルト)
→ クリック率(CTR)が上がる効果がある
→ Googleに強く推奨されている

例:検索結果での表示
example.com › ブログ › HTML › パンくずリストの実装方法

JSON-LD:
→ <script type="application/ld+json"> タグに
  JSONデータを書く方法
→ HTMLの構造を変えずに追加できる
→ Googleが推奨している形式

4.2 JSON-LDの基本実装

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>パンくずリストの実装方法 | ブログ名</title>

    <!--
        構造化データは <head> 内か <body> 内のどちらでもOK
        Googleは <head> 内を推奨
    -->
    <script type="application/ld+json">
    {
        "@context": "https://schema.org",
        "@type": "BreadcrumbList",
        "itemListElement": [
            {
                "@type": "ListItem",
                "position": 1,
                "name": "ホーム",
                "item": "https://example.com/"
            },
            {
                "@type": "ListItem",
                "position": 2,
                "name": "ブログ",
                "item": "https://example.com/blog/"
            },
            {
                "@type": "ListItem",
                "position": 3,
                "name": "HTML",
                "item": "https://example.com/blog/html/"
            },
            {
                "@type": "ListItem",
                "position": 4,
                "name": "パンくずリストの実装方法"
                /*
                    現在のページ(最後の項目)には
                    "item" を省略してもOK
                */
            }
        ]
    }
    </script>

</head>
<body>

    <nav aria-label="パンくずリスト">
        <ol class="breadcrumb">
            <li class="breadcrumb__item">
                <a href="/">ホーム</a>
            </li>
            <li class="breadcrumb__item">
                <a href="/blog/">ブログ</a>
            </li>
            <li class="breadcrumb__item">
                <a href="/blog/html/">HTML</a>
            </li>
            <li class="breadcrumb__item" aria-current="page">
                パンくずリストの実装方法
            </li>
        </ol>
    </nav>

</body>
</html>

4.3 PHPで動的に構造化データを生成する

<?php
/*
    WordPressでJSON-LDを動的に生成する
    functions.php に追加する
*/

function output_breadcrumb_json_ld() {
    // ホームページでは出力しない
    if ( is_front_page() ) {
        return;
    }

    $items   = [];
    $pos     = 1;
    $siteurl = home_url();

    // ① ホーム
    $items[] = [
        '@type'    => 'ListItem',
        'position' => $pos++,
        'name'     => 'ホーム',
        'item'     => $siteurl . '/',
    ];

    // ② カテゴリー(投稿ページの場合)
    if ( is_single() ) {
        $categories = get_the_category();
        if ( $categories ) {
            $category = $categories[0];
            $items[]  = [
                '@type'    => 'ListItem',
                'position' => $pos++,
                'name'     => esc_html( $category->name ),
                'item'     => get_category_link( $category->term_id ),
            ];
        }
        // ③ 現在の投稿
        $items[] = [
            '@type'    => 'ListItem',
            'position' => $pos,
            'name'     => esc_html( get_the_title() ),
        ];
    }

    // カテゴリーページの場合
    if ( is_category() ) {
        $items[] = [
            '@type'    => 'ListItem',
            'position' => $pos,
            'name'     => esc_html( single_cat_title( '', false ) ),
        ];
    }

    // 固定ページの場合
    if ( is_page() ) {
        // 親ページがある場合
        $parent_id = wp_get_post_parent_id( get_the_ID() );
        if ( $parent_id ) {
            $items[] = [
                '@type'    => 'ListItem',
                'position' => $pos++,
                'name'     => esc_html( get_the_title( $parent_id ) ),
                'item'     => get_permalink( $parent_id ),
            ];
        }
        // 現在の固定ページ
        $items[] = [
            '@type'    => 'ListItem',
            'position' => $pos,
            'name'     => esc_html( get_the_title() ),
        ];
    }

    // JSON-LD の出力
    $json_ld = [
        '@context'        => 'https://schema.org',
        '@type'           => 'BreadcrumbList',
        'itemListElement' => $items,
    ];

    echo '<script type="application/ld+json">';
    echo wp_json_encode( $json_ld, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
    echo '</script>';
}

// wp_head フックで出力する
add_action( 'wp_head', 'output_breadcrumb_json_ld' );
?>

5. 構造化データのテスト方法

Googleのツールで検証する:

① リッチリザルトテスト(推奨)
   URL:https://search.google.com/test/rich-results
   → URLを入力するか・コードを貼り付けて検証
   → エラー・警告・成功が表示される

② Schema Markup Validator
   URL:https://validator.schema.org/
   → スキーマの構文チェックができる

テスト手順:
① サイトにJSON-LDを実装する
② リッチリザルトテストのURLを開く
③ 「URLをテスト」タブでページのURLを入力する
   または「コードをテスト」タブにHTMLを貼り付ける
④ 「テスト」をクリックする
⑤ 「パンくずリスト」が検出されていれば成功

よくあるエラーと対処:
→ 「item が見つかりません」
   → "item" プロパティにURLを設定する
→ 「position が数値ではありません」
   → 文字列ではなく整数(1・2・3)で書く
→ 「name が見つかりません」
   → "name" プロパティを追加する

6. よくあるミスと対処法

6.1 HTMLの間違い

<!--
    ❌ NG:ul(順序なしリスト)を使っている
    → パンくずには順番があるので ol が正しい
-->
<nav aria-label="パンくずリスト">
    <ul class="breadcrumb">
        <li><a href="/">ホーム</a></li>
        <li><a href="/blog/">ブログ</a></li>
        <li>現在のページ</li>
    </ul>
</nav>

<!--
    ✅ OK:ol(順序付きリスト)を使う
-->
<nav aria-label="パンくずリスト">
    <ol class="breadcrumb">
        <li><a href="/">ホーム</a></li>
        <li><a href="/blog/">ブログ</a></li>
        <li aria-current="page">現在のページ</li>
    </ol>
</nav>

<!--
    ❌ NG:現在のページにリンクを付けている
-->
<li>
    <a href="/blog/html/this-page/">現在のページ</a>
    <!-- 自分自身へのリンクは不要 -->
</li>

<!--
    ✅ OK:現在のページはリンクなし・aria-current を付ける
-->
<li aria-current="page">現在のページ</li>

<!--
    ❌ NG:aria-label がない
    → 他のnavと区別できない
-->
<nav>
    <ol>...</ol>
</nav>

<!--
    ✅ OK:aria-label でナビゲーションを区別する
-->
<nav aria-label="パンくずリスト">
    <ol>...</ol>
</nav>

6.2 構造化データの間違い

javascript

// ❌ NG:positionが文字列になっている
{
    "@type": "ListItem",
    "position": "1",  // 文字列はNG
    "name": "ホーム",
    "item": "https://example.com/"
}

// ✅ OK:positionは整数
{
    "@type": "ListItem",
    "position": 1,    // 整数
    "name": "ホーム",
    "item": "https://example.com/"
}

// ❌ NG:URLが相対パスになっている
{
    "@type": "ListItem",
    "position": 1,
    "name": "ホーム",
    "item": "/"  // 相対パスはNG
}

// ✅ OK:URLは絶対パスで書く
{
    "@type": "ListItem",
    "position": 1,
    "name": "ホーム",
    "item": "https://example.com/"  // 絶対パス
}

// ❌ NG:HTMLのパンくずと内容が一致していない
// → HTMLでは「ホーム > ブログ > 記事」
// → JSON-LDでは「ホーム > 記事」(ブログが抜けている)
// → Googleにペナルティになる可能性がある

// ✅ OK:HTMLと構造化データの内容を一致させる

7. 実践チェックリスト

✓ <nav aria-label="パンくずリスト"> で囲んでいるか

✓ <ul> ではなく <ol> を使っているか

✓ 現在のページに aria-current="page" を付けているか

✓ 現在のページにリンクを付けていないか

✓ CSSのセパレーターは疑似要素(::before)で実装しているか

✓ JSON-LDのpositionは文字列ではなく整数で書いているか

✓ JSON-LDのitem(URL)は絶対パスで書いているか

✓ HTMLのパンくずリストとJSON-LDの内容が一致しているか

✓ リッチリザルトテストでエラーがないか確認したか


まとめ

今回はHTMLでパンくずリストを実装する方法として基本的なHTML実装・CSSスタイリング・構造化データ(JSON-LD)対応を解説しました。ポイントをまとめると:

  • パンくずリストは<nav aria-label="パンくずリスト">で囲み<ol>(順序付きリスト)を使う・<ul>(順序なしリスト)は不適切
  • 現在のページにはaria-current="page"を付けてリンクは付けない・スクリーンリーダーに現在地を伝えられる
  • セパレーター(区切り文字)はCSSの疑似要素(::before)で実装する・HTMLにセパレーターを直接書かない
  • スマートフォンでは直前の階層だけを表示するnth-last-child(2)のテクニックが有効
  • 構造化データ(JSON-LD)を追加することで検索結果にパンくずリストが表示されるリッチリザルトになる
  • JSON-LDのpositionは整数・item(URL)は絶対パスで書く・HTMLのパンくずリストと内容を一致させる
  • WordPressではYoast SEOのパンくずリスト機能を使うのが最もシンプルで確実
  • 実装後はGoogleのリッチリザルトテストでエラーがないか必ず確認する

次の記事では、HTMLのhead内の書き方を最適化する方法|読み込み順序とパフォーマンス改善をお届けします。お楽しみに!

コメント

タイトルとURLをコピーしました