はじめに
「WordPress高速化」シリーズの第6回です。【WordPress高速化】目次の高さを見出しの数で自動設定(以下「第5回の記事」)では、PHPで見出しを数えてCSS変数に渡し、SWELLの目次の高さを記事ごとに自動で確保しました。
ただ、第5回の記事の式は、目次の項目がすべてh2であることを前提にしています。SWELLの初期設定では、目次にh3まで入ります。h3の行はh2の行より低いので、第5回の記事の式のままでは、h3が多い記事ほど目次の下に余白ができます。
この記事では、第5回の記事の方法を広げて、次のようにします。
- PHP:目次に入るh2とh3を分けて数え、
--toc-n2・--toc-n3というCSS変数として出力する - CSS:「h2の行の高さ×h2の数+h3の行の高さ×h3の数」で、目次の
min-heightを計算する
あわせて、第5回の記事のコードでは数えられなかった、再利用ブロックやブログパーツの中の見出しも数えられるようにします。
この記事のコードは、SWELLの子テーマの functions.php と、カスタマイザーの「追加CSS」を使います。編集する前に、必ずバックアップを取ってください。
h3が入ると目次の高さはどう変わるか
h3の行は、h2の行より低い
テスト用の環境(Local)で、h2とh3を混ぜた記事を作り、目次の高さを測りました。目次の見出しは、第5回の記事のStep1と同じく、1行で「…」省略にしています。
| タブレット・パソコン | スマホ(画面幅599px以下) | |
|---|---|---|
| h2の1行 | 33.6px | 8.4vw(幅375pxで31.5px) |
| h3の1行 | 26.64px | 6.66vw(幅375pxで25.0px) |
h3の1行は、パソコンでh2より約7px、スマホ(幅375px)で約6.5px低くなります。

第5回の記事の式は、すべての項目をh2の高さで計算します。たとえば、h2が5つ・h3が10個の記事(目次の省略なし)では、パソコンで約70pxの余白ができます。ずれ(CLS)は出ませんが、h3が多いほど余白が大きくなります。
h3のまとまり方は関係ない
h3は、目次の中では一段下げた入れ子のリストになります。そこで、h3のまとまりの数で高さが変わるかも確かめました。
- 「h2・h3・h2・h3」(h3のまとまりが2つ)
- 「h2・h3・h3・h2」(h3のまとまりが1つ)
この2つは、どの画面幅でも同じ高さでした。目次の高さは、h2の数とh3の数だけで決まります。
目次の高さの式
画面幅320px〜1366pxの11段階、16パターンの記事で測った結果から、次の式が求まりました(誤差は0.3px以内)。
| タブレット・パソコン | スマホ | |
|---|---|---|
| 余白など(タイトル・枠の余白) | 103.7px | 9.7px+17.5vw |
| h2の1行 | 33.6px | 8.4vw |
| h3の1行 | 26.64px | 6.66vw |
| 「もっと見る」ボタン | 41.5px | 約46px-1.1vw |
h2だけの部分とボタンの値は、第5回の記事の式と同じです。第5回の記事の式に、h3の行を足した形になります。
SWELLの目次の数え方を確認する
PHPでSWELLの目次と同じ数を出すため、SWELLのJavaScriptを読んで、目次の作り方を確認しました。h3まで入れる場合は、次の点に注意が必要です。
- 「項目数で省略」は、h2とh3をまとめて数える:表示されるのは、h2・h3を文書の順に並べたときの先頭から「省略する数」個です
- 最初のh2より前にあるh3は、目次に入らない:記事の冒頭にh3を置いても、目次には表示されません
- 目次から外した見出しも、判定には数える:「目次を表示するか」「省略するか」の判定には、SWELLの「目次に表示しない」を付けた見出し(
swl-toc-off)も数に入ります - 再利用ブロックやブログパーツの中の見出しも数える:SWELLは、ページに表示された本文の見出しを数えます

たとえば「省略する数」が5で、「h2・h3・h3・h2・h3・h3・h2」の記事なら、表示されるのは先頭の5項目(h2が2つ、h3が3つ)と「もっと見る」ボタンです。この場合、目次の高さは「h2が2つ+h3が3つ+ボタン」で計算します。
3つ目と4つ目は、第5回の記事のコードでは扱っていませんでした。特に4つ目は、当サイトでも実際に起きていました。記事の最後に再利用ブロックで入れている見出しが数えられず、4本の記事で、目次の高さが1項目分(約31〜33px)足りませんでした。この記事のコードでは、この2つも直しています。
h3まで入れた目次の高さを自動設定する方法
Step1:目次の見出しを1行で表示する
第5回の記事のStep1と同じです。まだの場合は、「追加CSS」に次のCSSを追加します。
/* 目次の見出しを1行で表示し、はみ出た部分を「…」にする */
.p-toc__list a {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}見出しが2行に折り返すと、目次の高さが見出しの数だけでは決まらなくなるためです。理由は、第5回の記事で詳しく解説しています。
Step2:functions.phpでh2とh3を分けて数える
子テーマの functions.php に、次のコードを追加します。第5回の記事のコードを入れている場合は、そのコードと置き換えてください。
// 目次に入る h2・h3 を分けて数えて、CSS変数 --toc-n2・--toc-n3・--toc-more を出力する
add_action('wp_head', function () {
if (!is_singular() || !class_exists('SWELL_Theme')) {
return;
}
// 目次に入る見出しの階層(記事ごとの設定も反映される)。このコードは h3 までに対応
$target = apply_filters('swell_toc_target', SWELL_Theme::get_setting('toc_target'));
$max = min(3, (int) substr($target, 1)); // 'h3' → 3
// 再利用ブロックやブログパーツを展開してから、本文の見出しを順番に調べる
$content = do_shortcode(do_blocks(get_post_field('post_content', get_queried_object_id())));
preg_match_all('/<h([2-' . $max . '])\b([^>]*)>/', $content, $m, PREG_SET_ORDER);
$levels = []; // 目次に入る見出しの階層(2 か 3)を、順番に入れる
foreach ($m as $h) {
if (str_contains($h[2], 'swl-toc-off')) {
continue; // 目次から外した見出し
}
if (!$levels && $h[1] !== '2') {
continue; // 最初の h2 より前の h3 は、目次に入らない
}
$levels[] = (int) $h[1];
}
// 「表示するか」「省略するか」は、SWELLと同じく目次から外した見出しも含めた数で決める
$all = count($m);
if (!$levels || $all < (int) SWELL_Theme::get_setting('toc_minnum')) {
return;
}
$more = 0;
$omit = (int) SWELL_Theme::get_setting('toc_omit_num');
if (SWELL_Theme::get_setting('toc_omit_type') === 'ct' && $all > $omit + 1 && count($levels) > $omit) {
$levels = array_slice($levels, 0, $omit); // 表示されるのは、先頭から「省略する数」個
$more = 1;
}
$n = array_count_values($levels) + [2 => 0, 3 => 0];
echo '<style>:root{--toc-n2:' . $n[2] . ';--toc-n3:' . $n[3] . ';--toc-more:' . $more . '}</style>' . "\n";
});たとえば「h2・h3・h3・h2」の記事では、ページの <head> に次の1行が出力されます。
<style>:root{--toc-n2:2;--toc-n3:2;--toc-more:0}</style>コードのポイントは次のとおりです。
do_blocks()・do_shortcode():再利用ブロックやブログパーツを展開して、ページに表示される本文にしてから見出しを数えます$levels:目次に入る見出しの階層を、文書の順に[2, 3, 3, 2]のような配列に入れます。目次から外した見出しと、最初のh2より前のh3は入れません$all:目次から外した見出しも含めた数です。「表示するか」「省略するか」の判定は、SWELLと同じくこの数で行いますarray_slice():省略表示のときは、配列の先頭から「省略する数」個だけを残します。表示される項目のh2とh3の内訳が分かりますarray_count_values():配列の中の2と3の個数を数えます。+ [2 => 0, 3 => 0]は、h3がない記事でも--toc-n3:0を出すための書き方です
目次の設定が「h2まで」の場合も、このコードはそのまま使えます(--toc-n3 は常に0になります)。
Step3:追加CSSに目次の高さの式を書く
「追加CSS」に、次のCSSを追加します。第5回の記事のStep3のCSSを入れている場合は、そのCSSと置き換えてください。
/* 目次の高さ = 余白など + h2の行×h2の数 + h3の行×h3の数 + ボタン×(0か1) */
/* スマホ:画面幅599px以下 */
@media screen and (max-width: 599px) {
body .p-toc.-double {
min-height: calc(10.5px + 17.5vw + 8.4vw * var(--toc-n2, 5) + 6.66vw * var(--toc-n3, 0) + (46px - 1.1vw) * var(--toc-more, 1)) !important;
}
}
/* タブレット・パソコン:画面幅600px以上 */
@media screen and (min-width: 600px) {
body .p-toc.-double {
min-height: calc(104.5px + 33.6px * var(--toc-n2, 5) + 26.64px * var(--toc-n3, 0) + 42px * var(--toc-more, 1)) !important;
}
}- たとえば「h2・h3・h3・h2」の記事(
--toc-n2:2;--toc-n3:2;--toc-more:0)は、パソコンで104.5px+33.6px×2+26.64px×2=224.98pxになります(実際の高さは224.22px) - 式のpxの部分には、誤差を見込んで約0.8px足しています
var(--toc-n2, 5)などの2つ目の値は、CSS変数が出力されなかったときに使う予備の値です。「目次が最も高くなる場合」に合わせておきます。当サイト(省略する数5)なら「h2が5つ+ボタン」です
「省略しない」の設定(SWELLの初期値)では、目次の高さに上限がないので、予備の値は自分のサイトでよくある項目数(例:h2が6つ、h3が6つ)にしておきます。予備の値が使われるのは、functions.phpのコードを外したときなどだけです。
第5回の記事のコードから置き換える場合は、Step2のPHPとStep3のCSSを、必ず両方そろえて置き換えてください。片方だけだと、CSS変数の名前(--toc-n と --toc-n2)が合わず、高さが正しく計算されません。
Step4:検証ツールで確認する
- h3を含む記事を開き、F12で検証ツールを開く
- 「要素」パネルで
<head>の中を見て、<style>:root{--toc-n2:2;--toc-n3:2;--toc-more:0}</style>のような行が出力されているか確認する(Ctrl+Fで--toc-n2を検索すると早く見つかります) - 目次の項目を数えて、
--toc-n2・--toc-n3の数と合っているか確認する(省略表示の場合は、表示されている項目だけを数えます) - 「レンダリング」の「レイアウト シフト領域」をオンにして再読み込みし、目次の下が青く光らないか確認する

検証ツールの使い方は、【WordPress高速化】CLSの原因を検証ツールで探す方法で解説しています。
検証結果
Localで、次の記事を画面幅320px〜1366pxの7段階で確認しました。
- h2とh3の並びが違う19パターンの記事(h3が11個続く記事、20項目の記事、長い見出しの記事を含む)
- 目次から外した見出しがある記事、最初の見出しがh3の記事
- 再利用ブロック・ブログパーツ(ブロックとショートコード)の中に見出しがある記事
目次の設定は、「h3まで・省略しない」「h3まで・5個で省略」「h3まで・3個で省略」「h2まで・5個で省略」の4通りです。
目次が表示された539件すべてで、目次の本来の高さが min-height を超えることはなく、余白は0.74px〜1.4pxでした。PHPが出力した --toc-n2・--toc-n3・--toc-more の値も、実際に表示された目次の項目と全件で一致しました。
たとえば、次のような記事でも、SWELLの目次と同じ数になっています。
| 記事の見出し(文書の順) | 目次の設定 | SWELLの目次の表示 | 出力されたCSS変数 |
|---|---|---|---|
| h2×6、目次から外したh2×1 | h3まで・5個で省略 | h2×5+ボタン | --toc-n2:5;--toc-n3:0;--toc-more:1 |
| h3、h2×6 | h3まで・5個で省略 | h2×5+ボタン | --toc-n2:5;--toc-n3:0;--toc-more:1 |
| h2、h3、h3、h2、目次から外したh3×2 | h3まで・3個で省略 | h2×1、h3×2+ボタン | --toc-n2:1;--toc-n3:2;--toc-more:1 |
| h2×3、再利用ブロックの中のh2×1 | h2まで・5個で省略 | h2×4 | --toc-n2:4;--toc-n3:0;--toc-more:0 |
1つ目と3つ目は、目次に表示される項目だけを数えると「省略しない」と判定されてしまう例です。目次から外した見出しも判定に含めることで、SWELLと同じ結果になります。
注意点
- h4以上には対応していません:目次に h4 まで入れる設定では、h4 の行の高さを測って式に足す必要があります。このコードは h3 までを数えます
- 「階層で省略」「両方で省略」には対応していません:SWELLの目次の省略表示は、「項目数で省略」と「省略しない」の場合だけに対応しています
- ページ分割した記事:
<!--nextpage-->で記事を分けると、SWELLの目次はそのページの見出しだけを表示しますが、コードは記事全体の見出しを数えます - 目次やフォントサイズの設定を変えたとき:目次のデザイン、フォントサイズ、記事の幅などを変えると、行の高さも変わります。設定を変えたら、高さを測り直してください
- キャッシュ:キャッシュ系のプラグインやSWELLのキャッシュを使っている場合は、コードを追加したあとにキャッシュを削除してください
よくある質問・エラー対処
Q. 自分のサイトのh3の行の高さは、どうやって測ればよいですか
→ 「h2が2つ」の記事と「h2が1つ・h3が1つ」の記事を開き、検証ツールのコンソールで次のコードを実行して、目次の本来の高さを測ります。2つの差が「h2の行とh3の行の差」なので、h2の行の高さから引けばh3の行の高さが分かります。
// 目次の min-height を外して、本来の高さ(px)を表示する
const toc = document.querySelector('.p-toc.-double');
toc.style.setProperty('min-height', '0', 'important');
toc.getBoundingClientRect().height;スマホのフォントサイズが「デバイス可変」の場合は、画面幅を360pxと430pxの2つの幅で測り、第5回の記事のよくある質問と同じ方法で px+vw の式にします。
Q. 第5回の記事のコードを入れたまま、目次をh3までにしてもいいですか
→ ずれ(CLS)は出ませんが、h3の数だけ目次の下に余白ができます。第5回の記事のコードは、h3もh2の高さとして計算するためです。この記事のStep2・Step3のコードに置き換えてください。
Q. do_blocks() を使うと、ページの表示が遅くなりませんか
→ 本文のブロックを、ページを作るときにもう一度処理するので、その分だけPHPの処理が増えます。ただし、ページのキャッシュを使っていれば、この処理が行われるのはキャッシュを作るときだけです。
おわりに(まとめ)
SWELLの目次にh3まで入れている場合も、h2とh3を分けて数えれば、目次の高さを記事ごとに自動で確保できます。
- ✅ h3の1行は、h2の1行より低い(パソコンで約7px)
- ✅ 目次の高さは、h2の数とh3の数だけで決まり、h3のまとまり方は関係ない
- ✅ 省略表示のときは、先頭から「省略する数」個のh2とh3の内訳で計算する
- ✅ 再利用ブロックやブログパーツは、展開してから見出しを数える
- ✅ 「表示するか」「省略するか」の判定は、目次から外した見出しも数に入れる
この記事が、少しでも誰かのお役に立てれば幸いです。
関連記事
- 【WordPress高速化】HCBを必要な記事だけで読み込む:Highlighting Code BlockのCSSとJSを、コードブロックがある記事だけで読み込む方法(シリーズ第7回)
- 【WordPress高速化】目次の高さを見出しの数で自動設定:PHPで見出しを数えてCSS変数に渡し、目次の高さを記事ごとに自動で確保する方法(シリーズ第5回)
- 【WordPress高速化】SWELLのCLSをCSSで改善:目次や広告枠に min-height で高さを確保して、CLSを0.14から0.0008に下げた実例(シリーズ第2回)
- 【WordPress高速化】CLSの原因を検証ツールで探す方法:検証ツールで、ずれた場所を見つけて高さを測る方法(シリーズ第1回)
- 【WordPress高速化】AdSenseを枠ごとに遅延読み込み:広告枠が画面に近づいたときだけ広告を読み込む方法と、別の枠に広告が入ってしまう落とし穴の避け方(シリーズ第4回)
※1回買えば複数サイトで使い回しOK
当サイトの記事で使用したVBAなどのサンプルをDLできます
この記事のサンプルはありません!
ダウンロードページへは下のカードをクリックすればジャンプできます。
よろしければご利用ください!


