MENU

【WordPress高速化】SWELLのDOMサイズを減らす

【WordPress高速化】SWELLのDOMサイズを減らす
目次

はじめに

「WordPress高速化」シリーズの第10回です。PageSpeed Insights(PSI)で記事を計測すると、「DOM サイズを最適化する」という項目が表示されることがあります。以前は「過大なDOMサイズの回避」という名前だった項目です。当サイトの記事で、どこが要素を増やしているのかを数えてみました。

結果は次のとおりです。

  • SWELLでは、グローバルナビ(グロナビ)が、ヘッダー・追従ヘッダー・スマホメニューの3か所に出力されていて、ページの要素の約3分の1を占めていた
  • 見えていない部分も数に入る。スマホでは、PC用のグロナビと追従ヘッダーの約350要素が、表示されないまま数えられていた
  • 本文には手を付けずに、メニューの出し方を変えるだけで、要素数が1,232→924(約25%減)になった

この記事では、内訳の数え方と、SWELLでメニューの重複を減らす3つの方法を解説します。

WordPress 7.1.4、SWELL 2.19、Chrome 156 で確認しています。対策2の方法Bでは、SWELLの子テーマにファイルを追加し、functions.php を編集します。編集する前に、必ずバックアップを取ってください。

「DOM サイズを最適化する」とは

DOMは、ブラウザがHTMLを読み込んで作る、ページの部品(要素)の集まりです。<div> や <li>、<a> の1つ1つが要素として数えられます。

PSIの「DOM サイズを最適化する」を開いたところ(統計情報の表が見える状態)

PSIでは、「インサイト」の中に表示され、次の3つの数字が出ます。

項目意味上の画像の記事(PC)
合計要素数ページにある要素の数1,647
DOM の深さ要素が何重に入れ子になっているか(最も深いところ)21
子の最大数1つの要素の直下にある要素の数(最も多いところ)149(コードブロック)

上の画像では、子の最大数がVBAのコードブロックになっています。コードの色分けは、単語ごとに <span> で囲んで色を付けるため、長いコードほど直下の要素が増えます。DOM の深さについては、Googleの公式ドキュメントでも、深いこと自体は問題ではなく、不要な入れ子が多いことの目印として見るものとされています。

要素が多いと、ブラウザがスタイルを計算したり、配置(レイアウト)を計算し直したりする時間が長くなり、クリックしたときの反応が遅くなることがあります。メモリの使用量も増えます。

ただし、この項目は「スコアなし」と表示されていて、パフォーマンスのスコアに直接は加算されません。要素を減らしたからといって、スコアが大きく上がるわけではありません。

以前の基準と今の基準

PSIの計測に使われているLighthouseには、以前は「過大なDOMサイズの回避」という項目があり、bodyの中の要素が約800を超えると注意、約1,400を超えるとエラーになっていました。ネットで見かける「800」「1,400」という数字は、この基準です。

Lighthouse 13で、この項目は今の「DOM サイズを最適化する」にまとめられ、基準も変わりました。今は要素数そのものに基準の数字はなく、1回のスタイルやレイアウトの計算に40msを超える時間がかかったときに、警告として表示されます(公式ドキュメント:DOM サイズを最適化する)。要素が多いと、この計算が重くなりやすくなります。

見えていない要素も数に入る

注意したいのは、display:none で隠した要素も数に入ることです。SWELLの「PCのみ表示」「SPのみ表示」も、CSSで隠しているだけなので、要素はページに残っています。PCとスマホで別々の部品を用意して片方を隠す作り方は、両方の分だけ要素が増えます。

反対に、<iframe> の中身は数に入りません。広告や埋め込みの動画・SNSの投稿は、iframeの中に別のページとして読み込まれるので、元のページの要素数には含まれません。

内訳を数える:どこが要素を増やしているか

PSIでわかるのは合計だけなので、場所ごとの内訳を検証ツールで数えます。記事を開いて、検証ツール(F12)の「Console」タブで次のコードを実行します。

// SWELLのページで、場所ごとの要素数を数える
const count = (s) => {
	const el = document.querySelector(s);
	return el ? el.querySelectorAll('*').length + 1 : 0;
};
console.table({
	'合計': document.body.querySelectorAll('*').length,
	'ヘッダー': count('#header'),
	'追従ヘッダー': count('#fix_header'),
	'スマホメニュー': count('#sp_menu'),
	'本文': count('.post_content'),
	'記事下': count('#after_article'),
	'サイドバー': count('#sidebar'),
	'フッター': count('#footer'),
});
  • querySelectorAll('*').length:その要素の中にある、すべての要素の数です。自分自身の分として1を足しています
  • #header など:SWELLが出力する、それぞれの場所のIDです
  • console.table:結果を表の形で表示します

合計の数は、PSIの値と少しずれることがあります。PSIとは数えるタイミングが違うためです。どこが多いかを見るには、この数え方で十分です。

当サイトの結果

当サイトの記事4本を、ヘッドレスChromeで数えた結果です。

ページスマホPC
トップページ867867
VBAマクロの連続実行の記事1,2861,367
Power Queryのソース変更の記事1,1851,260
この前の第9回の記事1,4581,532

第9回の記事(スマホ)の内訳は、次のとおりです。

場所要素数スマホで見えるか
ヘッダー(うちグロナビ173)187グロナビは見えない
追従ヘッダー178見えない
スマホメニュー132閉じている
本文520見える
記事下(著者情報・関連記事5件)115見える
サイドバー134見える

本文以外の部分は、どの記事でもほぼ同じ数でした。本文が長い記事ほど、合計が増えていきます。

グロナビが3か所に出力されている

内訳を詳しく見ると、ヘッダーのグロナビ、追従ヘッダー、スマホメニューの中身は、どれも同じメニューでした。当サイトのグロナビは、親項目6つ・全47項目です。それが3回出力されて、合わせて約480要素になっていました。

SWELLではグローバルナビが、ヘッダー・追従ヘッダー・スマホメニューの3か所に出力される

SWELLのテーマのファイルを読むと、それぞれ次の理由で出力されています。

場所出力される理由
ヘッダーのグロナビ「グローバルナビ」に割り当てたメニュー。スマホでは隠している
追従ヘッダーカスタマイザーの「ヘッダーを追従させる(PC)」がオンのとき、グロナビをもう一度出力する。スマホでは隠している
スマホメニュー「スマホ開閉メニュー内」にメニューが割り当てられていないと、グロナビを代わりに出力する

追従ヘッダーは、JavaScriptで後から作られるのではありません。サーバーが最初から出力するHTMLに入っています。スマホでは、PC用のグロナビと追従ヘッダーの両方が隠れたまま残っていて、約350要素が表示されずに数えられていました。

手順:メニューの重複を減らす

Localに、当サイトと同じグロナビ(47項目)と、第9回と同じ本文のテスト記事を用意して、対策ごとの要素数を数えました。対策前は 1,232 です。

対策1:スマホメニュー用の短いメニューを作る

スマホメニューに、グロナビとは別の短いメニューを割り当てます。

  1. 外観 > メニュー で「新しいメニューを作成しましょう」をクリックし、スマホ用のメニューを作る(例:親カテゴリーだけの6項目)
  2. 「メニュー設定」の「メニューの位置」で 「スマホ開閉メニュー内」 にチェックを入れて、保存する

スマホメニューの要素は129→22になり、合計は 1,232→1,125(−107) になりました。スマホでは、メニューを開いたときに長い一覧が出なくなるので、読者にとっても選びやすくなります。

対策2:追従ヘッダーのグロナビを減らす

方法は2つあります。

方法A:PCの追従ヘッダーをオフにする

外観 > カスタマイズ > ヘッダー > ヘッダーの追従設定 の 「ヘッダーを追従させる(PC)」 のチェックを外します。追従ヘッダーが出力されなくなり、合計は 1,125→949(−176) になりました。

ただし、PCでスクロールしたときに、ページの上部にメニューが付いてこなくなります。スマホの追従(「ヘッダーを追従させる(SP)」)は別の設定なので、影響しません。

方法B:追従は残し、グロナビを表示するときにコピーする

PCの追従ヘッダーを残したい場合は、追従ヘッダーのグロナビを最初は出力せず、PCで追従ヘッダーが初めて表示されるときに、ヘッダーのグロナビをJavaScriptでコピーします。

まず、子テーマ(swell_child)に parts/header/fix_header.php というファイルを作り、次の内容を貼り付けます。フォルダ parts と header がない場合は作成してください。SWELLは、子テーマに同じ名前のファイルがあると、そちらを使います。

<?php
if ( ! defined( 'ABSPATH' ) ) exit;
// 追従ヘッダー:グロナビは出力せず、表示されるときにJavaScriptでコピーする
?>
<div id="fix_header" class="l-fixHeader <?=esc_attr( SWELL_Theme::get_header_class() )?>">
	<div class="l-fixHeader__inner l-container">
		<div class="l-fixHeader__logo">
			<?php echo SWELL_PARTS::head_logo( true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
		</div>
		<div class="l-fixHeader__gnav c-gnavWrap"></div>
	</div>
</div>

SWELL本体の parts/header/fix_header.php から、グロナビを出力する部分だけを取り除いたものです。ロゴと、グロナビを入れる空の枠は残しています。

次に、子テーマの functions.php に、次のコードを追加します。

// 追従ヘッダーが初めて表示されるときに、グロナビをコピーする(PCのみ)
add_action('wp_footer', function () {
	if (!SWELL_Theme::get_setting('fix_header')) return;
	?>
<script>
(() => {
	const gnav = document.querySelector('#gnav .c-gnav');
	const target = document.querySelector('.l-fixHeader__gnav');
	if (!gnav || !target || target.children.length) return;
	const pc = window.matchMedia('(min-width: 960px)');
	const copy = () => {
		if (target.children.length || !pc.matches) return;
		if (document.documentElement.getAttribute('data-scrolled') !== 'true') return;
		const clone = gnav.cloneNode(true);
		// 検索ボタンなどは、元のボタンのクリックとして動かす
		const src = gnav.querySelectorAll('[data-onclick]');
		clone.querySelectorAll('[data-onclick]').forEach((btn, i) => {
			btn.addEventListener('click', (e) => { e.preventDefault(); src[i].click(); });
		});
		target.appendChild(clone);
		observer.disconnect();
	};
	const observer = new MutationObserver(copy);
	observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-scrolled'] });
	pc.addEventListener('change', copy);
})();
</script>
	<?php
}, 99);
  • SWELL_Theme::get_setting('fix_header'):「ヘッダーを追従させる(PC)」がオフのときは、何もしません
  • data-scrolled:SWELLは、ページをスクロールしてヘッダーが画面から外れると、<html> の data-scrolled を "true" にして、追従ヘッダーを表示します。この変化を MutationObserver(要素の変化を見張る仕組み)で待ちます
  • matchMedia('(min-width: 960px)'):画面幅が960px以上(SWELLのPC表示)のときだけコピーします。スマホでは追従ヘッダーにグロナビを使わないので、コピーしません
  • cloneNode(true):ヘッダーのグロナビを、中身ごとコピーします
  • [data-onclick]:グロナビの検索ボタンは、SWELLがページを読み込んだときにクリックの処理を付けています。コピーしたボタンにはその処理が付いていないので、元のボタンをクリックしたことにして動かします
  • observer.disconnect():コピーは1回だけなので、見張りをやめます
  • pc.addEventListener('change', copy):画面幅が変わったときにも、コピーを試します。スマホの幅でスクロールしてから画面を広げると、data-scrolled は "true" のまま変わらないので、これがないとグロナビが空のままになります

合計は 1,125→957(−168) になりました。PCでスクロールすると、追従ヘッダーにグロナビ(169要素)がコピーされ、検索ボタンも開くことを確かめています。

方法Bは、読み込んだ直後の要素を減らすもので、PCでスクロールした後は要素が元の数に戻ります。スマホでは最後までコピーしないので、効果がそのまま残ります。

対策3:グロナビ自体を整理する

対策1と2で、グロナビの出力は1か所になります。そのうえで、ほとんど使われていない項目があれば、メニューから外します。

当サイトの「そのほかの記事」には、子項目が10件ありました。これを外すと、合計は 957→924(−33) になりました。

対策1と2をしていない状態で同じ10件を外すと、1,232→1,144(−88) でした。メニューが3か所に出力されているので、1項目減らすと3か所分減ります。メニューの説明文(項目の下に出る小さな文字)を入れた項目は、ヘッダーのグロナビと追従ヘッダーで、要素が1つずつ増えます。

実測:対策前後の比較

対策ごとの要素数。対策前1,232から、対策1で1,125、対策2の方法Bで957、対策3で924に減った
段階合計要素数減った数
対策前1,232–
対策1:スマホ用の短いメニュー1,125−107
対策2(方法B):追従ヘッダーのグロナビを後からコピー957−168
対策3:グロナビの子項目を10件外す924−33
合計−308(約25%減)

(対策2を方法Aにした場合は、対策2の後が949になります。)

時間はどれくらい変わったか

PSIのモバイルの計測と同じように、CPUの速さを4分の1に落として、ページを読み込むときのスタイルの計算時間を比べました(5回の中央値)。

対策前(1,144)対策後(924)
スタイルの計算(PC)約128ms約111ms
スタイルの計算(スマホ)約101ms約98ms

PCで1割ほど短くなりましたが、スマホではほとんど変わりませんでした。レイアウトの計算時間は、計測ごとのばらつきのほうが大きく、差がわかりませんでした。

要素を約2割減らしても、体感でわかるほど速くなるわけではありません。この対策の目的は、読者に見えないまま出力されている部品をなくして、ページを軽くしておくことです。

減らさなくてよいもの

要素の数だけを見ると、本文や目次、関連記事を削りたくなります。しかし、どれも読者が読むための部分です。PSIの数字を下げるために、記事の内容や読みやすさを削る必要はありません。

減らす対象は、今回のメニューのように、同じものが重複している部分や、表示されないまま出力されている部分に絞るのがおすすめです。

注意点

  • キャッシュを削除してから確かめる:SWELLのキャッシュやキャッシュ系のプラグインを使っている場合は、メニューや設定を変えたら削除してください
  • 方法Bは、SWELLの更新後に見直す:子テーマの fix_header.php は、SWELL本体のファイルの代わりに使われます。SWELLの更新で本体の fix_header.php が変わった場合は、子テーマのファイルにも同じ変更を反映してください
  • 方法Bの表示を確かめる:PCでスクロールして、追従ヘッダーにグロナビが出ること、サブメニューと検索ボタンが動くことを確かめてください

よくある質問・エラー対処

Q. PSIの「DOM の深さ」の最も深いところが、Googleのサイト内検索になっています

→ Googleのサイト内検索(プログラム可能検索エンジン)のウィジェットは、ページを読み込んだ後にJavaScriptで検索窓の部品を追加します。当サイトでも、最も深いところはその部品でした。テーマや記事の作りとは関係なく、Googleが用意している部品なので、気にしなくて大丈夫です。


Q. 要素数が800くらいでも、対策したほうがいいですか

→ 急いで対策する必要はありません。ただ、この記事のようにメニューが重複している場合は、スマホメニュー用の短いメニューを作る(対策1)だけで、手間をかけずに100要素ほど減らせます。


Q. 方法Bで、追従ヘッダーにグロナビが表示されません

→ 子テーマのファイルの場所が swell_child/parts/header/fix_header.php になっているか確認してください。あわせて、カスタマイザーの「ヘッダーを追従させる(PC)」がオンになっているか、画面幅が960px以上かも確認してください。

おわりに(まとめ)

まとめ

SWELLでは、本文を削らずに、メニューの重複を減らすだけで要素数を約25%減らせます。

  • ✅ PSIの「DOM サイズを最適化する」はスコアなしの項目。数字よりも、どこが要素を増やしているかを見る
  • ✅ 検証ツールのConsoleで、場所ごとの要素数を数えられる。隠した要素も数に入る
  • ✅ SWELLでは、グロナビがヘッダー・追従ヘッダー・スマホメニューの3か所に出力されることがある
  • ✅ スマホ用の短いメニューを「スマホ開閉メニュー内」に割り当て、追従ヘッダーのグロナビを減らす
  • ✅ 要素数は1,232→924になったが、時間の短縮は小さい。読者のための本文や目次は削らない

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

関連記事

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

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

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


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


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