MENU

【WordPress高速化】h3まで入れた目次の高さを自動設定

【WordPress高速化】h3まで入れた目次の高さを自動設定
目次

はじめに

「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.6px8.4vw(幅375pxで31.5px)
h3の1行26.64px6.66vw(幅375pxで25.0px)

h3の1行は、パソコンでh2より約7px、スマホ(幅375px)で約6.5px低くなります。

目次の行の高さの比較。h2の行は33.6px、h3の行は26.64px。h3が多いほど、全部h2として確保した高さとの差が大きくなる

第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.7px9.7px+17.5vw
h2の1行33.6px8.4vw
h3の1行26.64px6.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の7項目の記事では、先頭から5項目(h2が2つ、h3が3つ)と「もっと見る」ボタンが表示される

たとえば「省略する数」が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:検証ツールで確認する

  1. h3を含む記事を開き、F12で検証ツールを開く
  2. 「要素」パネルで <head> の中を見て、<style>:root{--toc-n2:2;--toc-n3:2;--toc-more:0}</style> のような行が出力されているか確認する(Ctrl+Fで --toc-n2 を検索すると早く見つかります)
  3. 目次の項目を数えて、--toc-n2・--toc-n3 の数と合っているか確認する(省略表示の場合は、表示されている項目だけを数えます)
  4. 「レンダリング」の「レイアウト シフト領域」をオンにして再読み込みし、目次の下が青く光らないか確認する
検証ツールの要素パネル。headの中に<style>:root{--toc-n2:…;--toc-n3:…;--toc-more:…}</style>が出力されている

検証ツールの使い方は、【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×1h3まで・5個で省略h2×5+ボタン--toc-n2:5;--toc-n3:0;--toc-more:1
h3、h2×6h3まで・5個で省略h2×5+ボタン--toc-n2:5;--toc-n3:0;--toc-more:1
h2、h3、h3、h2、目次から外したh3×2h3まで・3個で省略h2×1、h3×2+ボタン--toc-n2:1;--toc-n3:2;--toc-more:1
h2×3、再利用ブロックの中のh2×1h2まで・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の内訳で計算する
  • ✅ 再利用ブロックやブログパーツは、展開してから見出しを数える
  • ✅ 「表示するか」「省略するか」の判定は、目次から外した見出しも数に入れる

この記事が、少しでも誰かのお役に立てれば幸いです。

関連記事

当サイトの記事で使用したVBAなどのサンプルをDLできます

この記事のサンプルはありません!

ダウンロードページへは下のカードをクリックすればジャンプできます。
よろしければご利用ください!


【CSS】テキスト関連プロパティについて基本解説|Webの基礎


よかったらシェアしてね!
  • URLをコピーしました!
目次