スマホで長い記事を読んでいると、「今どのあたりだっけ?」「あの見出しまで戻りたい」ということがよくありますよね。Cocoonには目次機能がありますが、記事の上の方にあるので、読み進めるとすぐ見えなくなってしまいます。
そこで今回は、画面右下に「目次ボタン」を固定表示して、タップするとポップアップで目次が開く仕組みを作りました。あわせて、サイドバーの目次ウィジェットとの上手な使い分け方も紹介します。
Cocoon向けに作っていますが、少し書き換えるだけで他のWordPressテーマや目次プラグインでも使えます。そちらのやり方も後半で解説しています。
完成イメージ
完成すると、次のような動きになります。
| 表示 | 目次の見え方 |
|---|---|
| PC | 右下の目次ボタン(目次ウィジェットを残している場合はサイドバーの目次も表示) |
| スマホ | 右下の目次ボタンのみ(サイドバーの目次は非表示) |
目次ボタンをタップすると、画面中央に目次がポップアップで表示されます。見出しをタップするとその位置へジャンプして、ポップアップは自動で閉じます。背景の暗い部分や「×」をタップしても閉じられます。
仕組みの考え方
今回の目次ポップアップは、次の2つの工夫で作っています。
1. 開閉はCSSのチェックボックスで行う
非表示のチェックボックスと、それに紐づいたlabelを使っています。ボタン(label)をタップするとチェックがON/OFFに切り替わり、CSSの:checkedでポップアップの表示・非表示を切り替えます。開閉そのものにJavaScriptを使わないので、動きが軽くて壊れにくいのがメリットです。
2. 目次の中身は本文の目次をコピーする
目次を自前で作り直すのではなく、Cocoonが本文中に出力している目次(.toc-content)の中身をJavaScriptでポップアップにコピーしています。そのため、Cocoonの目次設定(表示する見出しレベルなど)がそのまま反映されます。
また、目次がない記事ではボタン自体を表示しないようにしています。見出しの少ない記事で、押しても何も出ないボタンが残ることはありません。
事前に確認すること
この仕組みはCocoonの目次をコピーして使うので、目次機能がONになっている必要があります。
管理画面の「Cocoon設定」→「目次」タブで、「目次を表示する」にチェックが入っているか確認してください。
また、作業前には子テーマのfunctions.phpとstyle.cssのバックアップを取っておきましょう。
ステップ1:functions.phpにコードを追加する
子テーマ(cocoon-child-master)のfunctions.phpの一番下に、次のコードを追加します。
// 目次ポップアップ(Cocoon用・CSSチェックボックス方式)
add_action( 'wp_footer', function () {
if ( ! is_singular( 'post' ) ) return;
?>
<input type="checkbox" id="toc-toggle" class="toc-toggle-checkbox">
<label for="toc-toggle" class="toc-fab" aria-label="目次を開く" style="display:none;">☰</label>
<label for="toc-toggle" class="toc-modal-overlay"></label>
<div class="toc-modal-box">
<label for="toc-toggle" class="toc-modal-close">×</label>
<div class="toc-modal-title">目次</div>
<div class="toc-modal-content-clone"></div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
var src = document.querySelector('.entry-content .toc-content') || document.querySelector('.toc-content');
var target = document.querySelector('.toc-modal-content-clone');
var fab = document.querySelector('.toc-fab');
var checkbox = document.getElementById('toc-toggle');
if (!src || !target || !fab) return; // 目次がない記事はボタンを出さない
target.innerHTML = src.innerHTML;
fab.style.display = '';
// 目次内のリンクを押したらポップアップを閉じる
target.addEventListener('click', function (e) {
if (e.target.closest('a')) {
checkbox.checked = false;
}
});
});
</script>
<?php
});コードのポイント
| 部分 | 役割 |
|---|---|
add_action( 'wp_footer', ... ) | ページの一番下(</body>の直前)にボタンとポップアップを出力 |
is_singular( 'post' ) | 投稿ページだけで表示(固定ページやトップページには出さない) |
☰ | ボタンのアイコン(三本線)。記号は数値文字参照で書いて文字化けを防止 |
.entry-content .toc-content | 本文中のCocoon目次を優先してコピー元にする |
style="display:none;" | 最初はボタンを隠しておき、目次が見つかったときだけ表示 |
コピー元を「本文中の目次」優先にしているのがポイントです。サイドバーに目次ウィジェットを置いている場合、そちらにも同じ.toc-contentがあるため、本文側を先に探すようにしています。
固定ページでも表示したい場合は、is_singular( 'post' )をis_singular()に変更してください。
ステップ2:style.cssにデザインを追加する
子テーマのstyle.cssの一番下に、次のCSSを追加します。スマホ表示時にサイドバーの目次ウィジェットを非表示にする設定もここに含まれています。
/* ===== 目次ポップアップ ===== */
.toc-toggle-checkbox {
display: none;
}
/* 目次を開くボタン(トップへ戻るボタンの上) */
.toc-fab {
position: fixed;
right: 20px;
bottom: 82px;
width: 48px;
height: 48px;
border-radius: 50%;
background: #fff;
border: 1px solid #ddd;
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
cursor: pointer;
z-index: 9999;
}
/* 背景の暗いオーバーレイ */
.toc-modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
z-index: 10000;
cursor: pointer;
}
/* ポップアップ本体 */
.toc-modal-box {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fff;
width: 90%;
max-width: 400px;
max-height: 80vh;
overflow-y: auto;
border-radius: 8px;
padding: 24px;
z-index: 10001;
}
.toc-modal-title {
font-weight: bold;
font-size: 18px;
margin-bottom: 12px;
}
.toc-modal-close {
position: absolute;
top: 12px;
right: 12px;
font-size: 24px;
cursor: pointer;
line-height: 1;
}
.toc-modal-content-clone ol,
.toc-modal-content-clone ul {
margin: 0;
padding-left: 1.5em;
}
.toc-modal-content-clone li {
margin: 6px 0;
line-height: 1.5;
}
/* チェックONで表示 */
#toc-toggle:checked ~ .toc-modal-overlay,
#toc-toggle:checked ~ .toc-modal-box {
display: block;
}
/* ジャンプ先の見出しが固定ヘッダーに隠れないように */
.entry-content [id^="toc"] {
scroll-margin-top: 100px;
}
/* スマホ時 */
@media screen and (max-width: 834px) {
/* ボタン位置(下部メニューと重ならない位置) */
.toc-fab {
bottom: 110px;
}
/* サイドバーの目次ウィジェットを非表示 */
#sidebar .widget_toc,
#sidebar-scroll .widget_toc {
display: none !important;
}
}保存したら、スマホで記事ページを開いて確認してみてください。右下に三本線のボタンが出ていれば成功です。
サイドバーの目次ウィジェットについて
Cocoonには標準で「[C] 目次」ウィジェットが用意されています。「外観」→「ウィジェット」から「サイドバー」や「サイドバースクロール追従」エリアに追加するだけで、サイドバーに目次を表示できます。
ただしスマホでは、サイドバーは記事本文の下に回り込みます。そのため目次ウィジェットは記事のずっと下まで読まないと出てこず、スマホではほとんど役に立ちません。
おすすめは目次ウィジェットを削除すること
今回の目次ボタンは、スマホだけでなくPCでも右下に表示されます。そのため、目次ウィジェットをサイドバーに入れたままだと、PCでは「サイドバーの目次」と「目次ボタン」の2つが表示され、役割が重複してしまいます。
目次ボタンがあれば、PCでもスマホでもいつでも目次を開けます。特にこだわりがなければ、「外観」→「ウィジェット」から「[C] 目次」を削除しておくのがおすすめです。サイドバーがスッキリして、他のウィジェットや広告を目立たせることもできます。
PCではサイドバーにも目次を表示したい場合
「PCでは読みながら常に目次が見えるほうがいい」という場合は、目次ウィジェットを残しておいても大丈夫です。
ステップ2のCSSには、スマホ表示時だけサイドバーの目次ウィジェットを非表示にするコードを入れてあります。
/* サイドバーの目次ウィジェットを非表示 */
#sidebar .widget_toc,
#sidebar-scroll .widget_toc {
display: none !important;
}このコードは画面幅834px以下のときだけ効くので、PCではサイドバーの目次がそのまま表示され、スマホでは非表示になります。目次ウィジェットを削除した場合は、このコードを残しておいても特に問題はありません。
使い方別のまとめ
| パターン | 目次ウィジェット | PCの表示 | スマホの表示 |
|---|---|---|---|
| おすすめ | 削除する | 目次ボタンのみ | 目次ボタンのみ |
| PCでもサイドバーに目次を出したい | 残す | サイドバーの目次+目次ボタン | 目次ボタンのみ(ウィジェットはCSSで非表示) |
834pxはCocoonが1カラム表示に切り替わる幅に合わせています。
カスタマイズ方法
よく調整しそうな箇所をまとめました。
| 変えたいこと | 変更する場所 |
|---|---|
| PCでのボタンの高さ | .toc-fabのbottom: 82px; |
| スマホでのボタンの高さ | メディアクエリ内のbottom: 110px; |
| ボタンを左側に出す | right: 20px;をleft: 20px;に変更 |
| ボタンの色 | .toc-fabのbackgroundとborder |
| ポップアップの横幅 | .toc-modal-boxのmax-width: 400px; |
| 見出しジャンプ時の余白 | scroll-margin-top: 100px;(固定ヘッダーの高さに合わせる) |
数値を少しずつ変えて、実際にスマホで見ながら調整するのがおすすめです。
Cocoonのモバイルボタンを使っている場合の注意
Cocoonでは「Cocoon設定」→「モバイル」で、画面下部に固定の「フッターモバイルボタン」を表示できます。これを有効にしていると、右下の「トップへ戻る」ボタンは非表示になるのがCocoonの仕様です。
その場合、目次ボタンだけが少し高い位置に浮いて見えることがあります。気になる場合は、スマホ用のbottomの値を小さくして、フッターモバイルボタンのすぐ上あたりに来るよう調整してください。
ちなみに、フッターモバイルボタンには独自コマンドで「目次へ」ボタンを追加することもできます。ただしこちらは本文中の目次の位置までジャンプするだけで、今回のようなポップアップとは別物です。
Cocoon以外のテーマやプラグインで使う方法
この仕組みはwp_footerフックを使っているので、Cocoon以外のWordPressテーマでもそのまま動きます。違うのは「どこから目次をコピーするか」だけです。
変更するのはJavaScriptの1行だけ
functions.php内の次の1行を、使っているテーマやプラグインの目次に合わせて書き換えます。
var src = document.querySelector('.entry-content .toc-content') || document.querySelector('.toc-content');たとえば、よく使われる目次プラグインでは次のように書き換えます。
| 目次の種類 | 書き換え例 |
|---|---|
| Cocoon標準の目次 | document.querySelector('.entry-content .toc-content') |
| Table of Contents Plus | document.querySelector('#toc_container .toc_list') |
| Easy Table of Contents | document.querySelector('#ez-toc-container nav') |
プラグインやテーマのバージョンによってクラス名が変わることがあるので、うまく動かない場合は次の方法で確認してください。
目次のクラス名を調べる方法
- PCのブラウザで記事ページを開く
- 目次の上で右クリック→「検証」(Chrome)または「調査」(Firefox)を選ぶ
- 目次のリスト(
olやul)を囲んでいる要素のclassやidを確認する - その名前を
querySelector()の中に書く(classなら先頭に「.」、idなら「#」を付ける)
見出しジャンプ位置の調整
CSSの.entry-content [id^="toc"]は、Cocoonの見出しIDが「toc1」「toc2」…となっているのに合わせた指定です。他のテーマでは見出しのIDが違うので、次のように本文の見出し全体に指定するのが簡単です。
.entry-content h2,
.entry-content h3,
.entry-content h4 {
scroll-margin-top: 100px;
}本文のクラス名もテーマによって違う場合があります(.post-content、.article-bodyなど)。同じく「検証」で確認して置き換えてください。
サイドバーの目次を非表示にする部分
スマホ時にサイドバーの目次を消すCSS(.widget_tocの部分)はCocoon専用です。他のテーマでは、目次ウィジェットのクラス名とサイドバーのIDを調べて書き換えるか、不要なら削除してください。1カラムに切り替わる幅(834px)も、テーマに合わせて変更しましょう。
WordPress以外のサイトで使う場合
静的なHTMLサイトなどでは、functions.phpの?>から<?phpまでの間にあるHTMLとscript部分を、ページの</body>の直前に直接貼り付ければ動きます。CSSはサイトのスタイルシートに追加してください。この場合も、目次を作る仕組みが別途必要です。
うまく動かないときのチェックポイント
| 症状 | 確認すること |
|---|---|
| ボタンが表示されない | Cocoon設定で目次がONか、記事に見出しが十分あるか(目次がない記事ではボタンは出ません) |
| ボタンを押しても中身が空 | コピー元のquerySelector()がテーマの目次と合っているか |
| アイコンが「?」に化ける | 記号を生の文字で書いていないか(☰のような数値文字参照で書く) |
| 見出しが固定ヘッダーに隠れる | scroll-margin-topの値を大きくする |
| PCで目次が2つ表示される | サイドバーに「[C] 目次」ウィジェットが残っていないか(不要なら削除) |
| スマホでサイドバーの目次が消えない | 目次ウィジェットのクラス名がwidget_tocになっているか「検証」で確認 |
| 変更が反映されない | Cocoonのキャッシュやブラウザのキャッシュを削除して再確認 |
まとめ
今回は、記事を読みながらすぐに目次を開ける「目次ポップアップ」を作りました。
- 開閉はCSSのチェックボックス方式で軽量
- 目次の中身はCocoonの目次をコピーするので設定がそのまま反映
- 目次がない記事ではボタンを自動で非表示
- 目次ボタンはPCにも出るので、サイドバーの目次ウィジェットは削除がおすすめ
- PCでサイドバーにも目次を出したい場合は、スマホ時だけCSSで非表示にできる
- コピー元の1行を変えれば他のテーマやプラグインでも使える
目次ボタン1つでPCでもスマホでもいつでも目次を開けるので、長めの記事が多いサイトには特におすすめのカスタマイズです。






コメント