Googleのブログサービス「Blogger」のテンプレート・カスタマイズ・TIPSなどを紹介しています

2026/02/20

【Blogger専用】サイドバースクロール追従&ハイライト機能付きの目次

event_note2/20/2026 editBy まつゆう forumNo comments

「記事が長くなってきて、どこに何が書いてあるか分かりにくい……」
「読者が知りたい情報にたどり着く前に離脱していないか心配……」

Bloggerでブログを運営していると、標準機能に「目次」がないことに不便を感じることはありませんか?外部スクリプトを導入しても、デザインが崩れたり、設定が複雑だったりして諦めてしまった方も多いかもしれません。

そこで今回は、Bloggerユーザーのために設計した「コピペだけで導入できて、しかも高機能」な自作目次スクリプトをご紹介します。

実際の動作を確認できます
このページでも、実際にサイドバーにこの目次を設置しています。スクロールに合わせて目次が追いかけてきたり、現在地がハイライトされたりする様子をぜひチェックしてみてください。

今回の目次スクリプトの主な機能

  • 自動生成: 記事内の見出し(h2, h3)を自動で抽出してリスト化します。
  • 階層構造への対応: h3見出しは自動的に字下げされ、視覚的に分かりやすくなります。
  • スクロール追従: PC閲覧時、記事を読み進めても目次がサイドで追いかけてきます(Sticky機能)。
  • 現在地ハイライト: 今読んでいるセクションに合わせて、目次の色をリアルタイムで切り替えます。

本記事での表示例(動作サンプル)

この記事では、実際にこのスクリプトをサイドバーに設置しています。今、あなたの画面のサイドバー(スマホの場合は本文上部など)に表示されている目次は、以下の見出し構成を元に自動生成されたものです。

  • h2:導入コード(HTML/CSS/JavaScript)
    • h3:デザインを司るCSS
    • h3:動的な処理を行うJavaScript
  • h2:カスタマイズのポイント

スクロールに合わせて、該当する見出しが青くハイライトされるのが確認できるはずです。実際の動きが分かったところで、導入手順に進みましょう。


導入方法:レイアウトに貼るだけで完了

このカスタマイズの最大の特徴は、Bloggerの「レイアウト」画面からガジェットを追加するだけで動作する点です。テーマのHTMLを直接編集する必要がないため、初心者の方でも安心です。

  • Blogger管理画面の「レイアウト」を開く。
  • サイドバー(または本文上部など)の「ガジェットを追加」をクリック。
  • 「HTML/JavaScript」を選択し、以下のコードをすべて貼り付けて保存。

導入コード(HTML/CSS/JavaScript)


<div class="my-toc-outer-box" id="my-toc-widget">
  <div class="my-toc-header-title">CONTENTS</div>
  <div class="my-toc-content-list" id="my-toc-list-body">
    <!-- ここに自動で目次が生成されます -->
  </div>
</div>

<style>
.my-toc-outer-box {
  background: #ffffff;
  border: 1px solid #ddd;
  border-radius: 5px;
  padding: 15px;
  margin-bottom: 20px;
  box-sizing: border-box;
}

@media screen and (min-width: 769px) {
  .my-toc-outer-box {
    position: -webkit-sticky;
    position: sticky;
    top: 20px;
    z-index: 10;
  }
}

.my-toc-header-title {
  font-weight: bold;
  font-size: 15px;
  border-bottom: 2px solid #333;
  margin-bottom: 10px;
  padding-bottom: 5px;
}

.my-toc-content-list ul { list-style: none !important; padding: 0 !important; margin: 0 !important; }
.my-toc-content-list li { margin: 8px 0 !important; line-height: 1.4 !important; }
.my-toc-content-list a { text-decoration: none !important; color: #555 !important; font-size: 13px !important; display: block !important; }

.my-toc-content-list a.active {
  color: #2196F3 !important;
  font-weight: bold !important;
  border-left: 3px solid #2196F3 !important;
  padding-left: 8px !important;
}
</style>


<script>
(function() {
    const CONFIG = {
        minHeadings: 2,
        scrollOffset: 80,
        activeOffset: 100
    };

    window.addEventListener('load', function() {
        const postBody = document.querySelector('.post-body, .entry-content');
        const tocArea = document.getElementById('my-toc-list-body');
        const container = document.getElementById('my-toc-widget');
        
        if (!postBody || !tocArea) return;

        const headings = Array.from(postBody.querySelectorAll('h2, h3'));
        if (headings.length < CONFIG.minHeadings) {
            container.style.display = 'none';
            return;
        }

        const ul = document.createElement('ul');
        headings.forEach((h, i) => {
            const id = 'my-toc-item-' + i;
            h.id = id;
            const li = document.createElement('li');
            if (h.tagName === 'H3') li.style.paddingLeft = '15px';
            
            const a = document.createElement('a');
            a.href = '#' + id;
            a.textContent = h.textContent;
            a.className = 'my-toc-link';
            
            a.addEventListener('click', e => {
                e.preventDefault();
                const targetPos = h.getBoundingClientRect().top + window.pageYOffset - CONFIG.scrollOffset;
                window.scrollTo({ top: targetPos, behavior: 'smooth' });
            });
            
            li.appendChild(a);
            ul.appendChild(li);
        });
        tocArea.appendChild(ul);

        const tocLinks = tocArea.querySelectorAll('.my-toc-link');
        window.addEventListener('scroll', () => {
            let activeId = "";
            const scrollPos = window.scrollY + CONFIG.activeOffset;
            headings.forEach(h => {
                if (h.offsetTop <= scrollPos) {
                    activeId = h.id;
                }
            });
            tocLinks.forEach(link => {
                link.classList.toggle('active', link.getAttribute('href') === '#' + activeId);
            });
        });
    });
})();
</script>


動作に関する補足

追従するのは「目次ガジェット」だけ

本コードで設定している「スクロール追従(Sticky機能)」は、このコードを記述したガジェットのみに適用されます。サイドバーにある他のガジェットが一緒に追いかけてくることはないので、非常にスマートです。

CSS

CSS部分では、独自のクラス名を使用し、Bloggerの他要素とスタイルが干渉しないように設計しました。ハイライトカラーは、お好みに合わせて変更可能です。

JavaScript

見出しの抽出からハイライトの切り替えまで、すべて自動で行います。多くのブラウザで安定して動作するスクロールイベントを採用しています。


カスタマイズのポイント

設定項目 役割
minHeadings 目次を表示するために必要な最小見出し数。
scrollOffset クリックした際、見出しの少し上で止まるように調整します。
activeOffset 画面のどの位置まで見出しが来たらハイライトを切り替えるかの判定距離です。

まとめ

お疲れ様でした。これで、あなたのブログにユーザビリティの高い目次が実装されたはずです。

目次は読者が読みたい場所にすぐにアクセスできる「地図」です。最後までストレスなく記事を楽しんでもらうための「おもてなし」として、ぜひ活用してみてください。

まつゆう
アラフォーゲーマーがいろんなゲームを楽しみながらプレイしています。YouTube・Twitch・Mixerで配信中!! 東京パフォーマンスドールの狂信者。 好きすぎてドメインを取得してファンサイトを運営中。

0 comments:

コメントを投稿