重いワードプレスサイトをそこそこの速さで表示するための方法いろいろ

新着情報

このサイトの目的

なぜ速度が重要なのか

スマートフォンによるインターネットへのアクセス割合がパソコンの割合を超えた(参考サイト)というニュースを聞いたのがしばらく前のことになります。
スマートフォンはパソコンに比べて通信速度も処理速度も遅いのですがスマートフォンユーザーはパソコンユーザーよりも気が長いということはありません。同じくらいの速度で表示してほしいと思っています。

どのくらいの影響があるのか

Webサイトの読み込み時間とユーザーの直帰率の関係は調査したサイトによってまちまちですが(参考サイト)読み込みに3秒以上かかったら半数は帰ってしまうと認識する必要があります。
また、読み込みが遅いことはSEOにも悪影響が出ます(参考サイト)
Googleは2018年11月に自社公式のページ速度測定サイトであるPageSpeed Insightsの大幅な仕様変更を行いました。内容としてはモバイルサイトの評価の基準を変更し、「速度改善に有効な対策をどのくらいしているか」という理論値を重視するシステムからLighthouseというツールを使って実際の読み込み時間速度を重視するシステムになりました。

Googleはユーザーにとっての自社のサービスの価値を上げるために良質なコンテンツをより検索結果の上位にインデックスされるように努めています。 良質なコンテンツとはサイトの内容そのものがユーザーにとって有益なものであることが重要ですがユーザー体験を向上させることも重要です。 複雑なページ構成を簡潔にしたりボタンを押しやすく、わかりやすい物にしたりするのと共にページの読み込みが速いこともユーザー体験を向上させる要因の一つです。

PageSpeed Insightsは速度評価サイトであると同時にWebサイトそのものの評価サイトでもあり、ページの読み込み速度が早いということはそれだけユーザーのストレスを無くすことになり、ページそのものも良質なものであると認識されるため検索結果の上位に入りやすくなります。
ユーザー体験、SEOの双方の意味でWebサイトにとっては速度が重要なのです。

ワードプレスは遅い

まず静的サイトと動的サイトについて説明します。
静的サイトとは… アクセスされたページをそのままクライアントに返す仕組みのサイト。すでに出来上がっているページをそのまま表示するため読み込みが速い。
動的サイトとは… アクセスされるたびにクライアントの必要としているページをサーバー上で構築し、その処理結果をクライアントに返す仕組みのサイト。無料ブログサービスやWordpressなどが代表。
このサイトは静的サイトに比べて遅いと言われるワードプレスサイト(動的サイト)を少しでも速くすることを目的にしています。

ファーストビューの重要性

ユーザーが最初にこのサイトに訪れたときファーストビューをもとに有益な情報があるかどうか判断する時間は3秒(参考サイト)と言われるため、この領域の読み込み時間を迅速に行い、かつユーザーが興味を持つようなコンテンツや有用な情報を載せる必要があります。

では、どうやって速くするのか

それをこれから説明していきます。

CSS内に画像を埋め込む

画像を大量に読み込むとHTTPリクエストが大量に発生してページの読み込みが遅くなります(参考サイト)
それを回避するためにData URIという技術を使います。これはBase64というエンコード方法によって画像などのファイルを文字データにしてCSSファイルの中に埋め込むことで小さなファイルを大量に転送するよりもHTTPリクエストやヘッダのトラフィックを軽減することができます。

エンコードすることでデータの容量が37%程増えてしまいますがトラフィック軽減によるメリットのほうが大きいため速度改善の効果があります。データ容量が増大するデメリットはHTTPサーバーからのレスポンスを gzip圧縮することで2~3%程度に抑えることができます。gzipについては後で説明しますが現在使っているエックスサーバーの場合何もしなくても自動でgzipにしてくれますしそうでないサーバーを使っている場合でも.htaccessから簡単に設定できます。

それでは、Data URIを使った場合とそうでない場合を比較してみましょう。とりあえず「何の対策もしていない場合」からご覧下さい。

動画やグーグルマップの読み込み遅延

動画ファイルやグーグルマップを貼り付けるとページの読み込みが遅くなります。動画1つのほうが画像1枚よりもファイル容量が圧倒的に大きいので遅延読み込みによるユーザーストレスの軽減効果も大きくなります(参考サイト)
遅延させるためのやり方は違いますがやっていることは基本的に画像の遅延読み込みと同じで、通常の方法では動画を全部読み込んでからページを表示するため重い動画を貼り付けると読み込み時間が遅くなりますが遅延読み込みを使うとページの他の部分を先に読み込んでからスクロールしないと表示されない部分を読み込むことでページ本体の読み込み時間を速くしています。

グーグルマップも見た目のシンプルさとは裏腹にかなり重いです。大抵のサイトではグーグルマップはフッターに1つ表示しているだけなので関係ないと思いがちですがその1つしかないグーグルマップがページ全体の読み込み速度をかなり遅くしています。

それでは、遅延読み込みを使った場合とそうでない場合を比較してみましょう。とりあえず「何の対策もしていない場合」からご覧下さい。

画像を減らす

Webサイトのデータサイズのほとんどを占めるのは画像です。画像は圧縮してもテキストに比べて非常にデータサイズが大きいので少しでも減らす努力をするべきです。

それでは、遅延読み込みを使った場合とそうでない場合を比較してみましょう。とりあえず「何の対策もしていない場合」からご覧下さい。

小ネタまとめ

(参考サイト)https://www.kagoya.jp/howto/webhomepage/http-2/
(参考サイト)https://knowledge.sakura.ad.jp/7734/
Webサイトのデータを取得するための通信方式(プロトコル)のこと

HTTP/1.0 基本
1996公開 サーバーに対して1つずつリクエストを送る 1つファイルをリクエストするとそのファイルがレスポンスされるまで次のリクエストは処理待ち状態になる。

HTTP/1.1
1999公開 サーバーに対して同時に複数のリクエストを送ることができる。が必ずリクエストされた順にレスポンスする
要求された順に処理するので重いファイルがあるとその後に要求されたファイルが処理待ちのために遅くなる

HTTP/2
2015公開 サーバーに対して同時に複数のリクエストを送ることができる
ストリームの概念を導入して複数のリクエスト/レスポンスを同時並行で処理できるように
ストリームは独立しているため重いファイルをリクエストしても待たされるのはそのストリームのみで他のストリームは影響を受けない

HTTP/2を使うにはどうすればいいのか
エックスサーバーやさくらインターネットなどはhttpsに対応するだけで自動的にHTTP/2が有効になる。逆に言うとほとんどのブラウザではhttpsにしないとHTTP/2を利用できない。
また、HTTP/1.1と/2ではファイルの読み込みを速くするためのやり方が大きく異なるためちゃんと理解しておかないと逆に遅くなることもある。

サーバーが自動でHTTP/2にしてくれない場合
.htaccessを書き換えればいい。
参考サイト:https://www.xserver.ne.jp/manual/man_server_htaccess.php

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

上記のようになっているので下記の部分だけ変更すればいい。

RewriteCond %{HTTPS} off → !on
		RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L] → [R=301,L]

どうやって確認すればいいのか
ChromeのデバッグモードにしてNetworkタブを選択してProtocolが「h2」や「http/2+quic46」になっていればOK

(参考サイト)https://qiita.com/kofuk/items/d1de158a746be73634fe
(参考サイト)https://deepdweb.com/css-js-load/
head内で外部CSSやJSを読み込むとその読み込み完了までレンダリングが終わらない=ページ本体の読み込みが遅れる
外部ファイルを読み込んでいる最中はレンダリングが止まるので外部ファイルはfooterで読み込む(JSファイルは速度に与える影響が大きいので更ににdeferを付けて遅延させる)

CSSとJSでは必ずCSSを読み込んでからJSを読み込む。
外部CSSはレンダリングを止めないが外部JavaScriptはレンダリングを止める。
CSSをhtml内にインライン展開すれば外部ファイルを読み込むより速く表示できるが管理が煩雑になる問題がある。ファーストビューの範囲のみクリティカルCSSを作成してインライン展開するのが手頃な妥協点。
CSSファイルどうしの順番:CSSは後書き優先なので サニタイズ → 基本となるCSS → 個別のCSSの順に読み込む。クリティカルCSSは最優先
JSファイルどうしの順番:jqueryが必要なコードはjqueryを先に読み込んでいないと動かないので jQuery本体 → script.js → 追加したjs のような順に

どこで読み込むのが最適か (参考サイト)https://naoyu.net/wp_enqueue_scripts/
CSSは<head>内、JSは<footer>と分けるとどのファイルを読み込んだか分かり辛くなるので全部functions.phpで管理するのがおすすめ。functions.phpに外部ファイルの読み込みを記述してアクションフックを使って</body>直前で読み込む

define("DIRE", get_template_directory_uri());	//(テーマディレクトリまでのパスを定数に)
function add_css(){
	wp_enqueue_style('sanitize', DIRE.'/css/sanitize.css');
	//wp_enqueue_style('style',DIRE.'/style.css', array());	クリティカルCSSを用意していないのでこれだけはhead内で読み込む
	wp_enqueue_style('lower',DIRE.'/lower-style.css', array());
	wp_enqueue_style('vegas2','//jaysalvat.github.io/vegas/releases/latest/vegas.min.css');
}
//通常<head>内で読み込むことになるのをwp_footerを入れた位置で読み込むよう変更
add_action('wp_footer', 'add_css');

//ここからJS部分
function add_js(){
	// wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer ); in_footerがtrueなら</body>前、falseなら</head>前に出力
	wp_enqueue_script('jquery_cdn', '//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js', array(), false, true);
	wp_enqueue_script('script', DIRE.'/js/script.js', array('jquery_cdn'), false, true);
	wp_enqueue_script('vegas2', '//jaysalvat.github.io/vegas/releases/latest/vegas.js', array('jquery_cdn'), false, true);
	wp_enqueue_script('scrollmagic', '//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/ScrollMagic.min.js', array('jquery_cdn'), false, true);
	wp_enqueue_script('prettify', '//cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js', array(), false, true);
	wp_enqueue_script('lazysize', DIRE.'/js/lazysizes.min.js', array('jquery_cdn'), false, true);
	wp_enqueue_script('lazyloader', DIRE.'/js/lazyloader.js', array(), false, true);
}
add_action('wp_enqueue_scripts', 'add_js');

クリティカルCSSとは
ファーストビューで見える範囲のコンテンツの表示に必要なCSS。ファーストビューの重要性については前に述べたがクリティカルレンダリングパスを最適化するためにファーストビューの表示に必要な分のCSSを抜き出して<head>内にインラインCSSとして展開することで外部CSSを読み込んでいる間のレンダリングブロックを回避することができる。

クリティカルCSSを利用する方法
このサイトhttps://www.sitelocity.com/critical-path-css-generatorでサイトURLを入れてボタンを押す → Critical Path CSS の中身を全てコピー → <head>内にペースト、という流れが一番楽。タスクランナーが使える人はそちらでいい。

クリティカルCSSのデメリット
・うまくいかないとサイトをリロードしたときにCSSなしの状態が見えてしまうことがある
・CSSの読み込みは後回しにしているだけなので回線速度が遅いとページ閲覧中にスクロールが突っかかることがある
・(CSSで読み込んでいる)背景画像の読み込みが間に合わずエラーが出る。画像そのものはちゃんと表示される
・クリティカルCSSそのもののサイズが大きくなる。小さくしようとするとデザインに影響が出て何のための技術かということに
・ファーストビューの範囲を決めるためにはユーザーの平均解像度を意識する必要がある。これはレスポンシブデザインの流れに逆行している
・サイトのトップ付近をいじるたびにクリティカルCSSを再生成するのが面倒
・PCとSPが別テーマになっているサイトの場合はまずPCテーマを有効にしてPC用クリティカルCSSを作成→SPテーマを有効にしてSP用クリティカルCSSを作成、と二度手間になる

(参考サイト)https://alaki.co.jp/blog/?p=2310
gzip圧縮とは
Webサイトの表示に必要な「テキストファイル」を1ファイルごとに圧縮して読み込む形式のことで、通常の方法よりもWebサイトを高速に読み込むことができる。テキストファイル以外も圧縮できるが画像ファイルはもともと圧縮されているためgzip圧縮すると逆に容量が大きくなるので通常はテキストファイルにしか適用されない。
どうやって使うのか
サーバー側でgzip圧縮を有効にする必要がある。「.htaccess」にコードを追加するのが一般的なやり方。このサイトで使っているエックスサーバーやさくらインターネットなどは.htaccessに何もしなくても自動でgzip圧縮されるサーバーもあるので先に自分のサーバーの設定を調べたほうがいい。
サーバーが自動でgzip圧縮してくれない場合
.htaccessの書き換えを行う。mod_deflateとmod_rewriteの2つのやり方がある。
mod_deflate: サーバーでファイルのgzip圧縮を行う。コードが短く簡単だがサーバーに負荷がかかるのでサーバーによっては禁止されていることも。
mod_rewrite: 事前にgzip圧縮したファイルを使ってgzipでファイルを転送するのでサーバーの負荷が少ない。自分でgzip圧縮する必要がある。

mod_deflateを使ったやり方

<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|ico|)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI _\.utxt$ no-gzip
#DeflateCompressionLevel 4
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom_xml
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/x-httpd-php
</IfModule>

mod_rewriteを使ったやり方
まずhtmlやcssなどのテキストファイルをgzip圧縮する必要があります。フリーソフトのLhaplusや7-Zipなどでファイルを右クリックして圧縮するのが簡単です(黒い画面からコマンドで変換できる人はそちらのほうが速いです)。
(参考サイト)https://hyper-text.org/archives/2012/11/webcontents_gzip.shtml
圧縮できたらstyle.css.gzのように拡張子がついたファイルができるので元のファイルと同じディレクトリにアップロードしましょう。元のファイルはgzip圧縮に対応していないブラウザの人に必要なので消さないで下さい。
次に.htaccessに.gz拡張子のファイルを送信するように設定します。

# RewriteEngine を有効にする
RewriteEngine On

# gzipで書き換えるディレクトリを指定。このままなら.htaccess以下のフォルダ全部が対象
RewriteBase /

# Accept-Encoding ヘッダをみて、gzip があれば(つまり gzip に対応した相手なら)処理を続行。なければ終わり。
RewriteCond %{HTTP:Accept-Encoding} gzip

# 送信リクエストされたファイル名に対して、.gz がついたファイルがあるか調べて、あれば次の行へ。なければここで終了。
RewriteCond %{REQUEST_FILENAME}¥.gz -s

# リクエストされたファイル名 + .gz のファイルを返す。
RewriteRule .+ %{REQUEST_URI}.gz

※Wordpressを使っている場合、自動で#BEGIN Wordpress~という記述が入る。その中に上述したコードと同じような部分があるので注意が必要。
両方使える状況ならmod_deflateのほうが手間がかからなくておすすめ。

どうやって確認すればいいのか
ChromeのデバッグモードにしてNetworkタブを選択してなにかテキストファイルをクリックして「ResponseHeaders」の「content-encoding」が「content-encoding: gzip」になっていればOK

画像の切り替え
レスポンシブサイトでユーザーが使っている端末によってパソコン用やスマホ用の画像に切り替える方法です。
高速化じゃないのかと思われるかもしれませんがスマホの小さい画面で無意味に大きな画像を読み込むことは無駄なトラフィックを発生させることになり結果的にWebサイト表示にかかる時間を増大させます。

スマホで画像がぼやける
(参考サイト)https://junzou-marketing.com/responsive-image
スマートフォンは年々飛躍的に高解像度化しており、Retinaディスプレイのように実際の解像度の2倍3倍のピクセル数をもつ端末も当たり前になっています。
それによって引き起こされる問題が「高解像度のスマホでWebサイトを見たときに画像がぼやける」です。
例えば幅1500pxのスマホで幅500pxの画像を表示したとすると500ピクセルの画像を無理やり3倍に引き伸ばして表示しているためぼやけてしまいます。

どうすればいいのか
パソコンで見たときはパソコン用の画像、スマホで見たときは解像度によって低解像度スマホ用画像と高解像度スマホ用画像を切り替え、という形がいいと思います。タブレットはとりあえずパソコン用の画像を表示します。

実際の解像度が767以下 & density(デバイスピクセル比)が3以上なら高解像度スマホ用画像に
実際の解像度が767以下 & density(デバイスピクセル比)が3未満なら低解像度スマホ用画像に
実際の解像度が768以上ならパソコン用画像に

<div class="imgwrap">
	<picture>
		<source media="(max-width: 767px)"
				srcset="<?php echo get_template_directory_uri(); ?>/images/index/sp/gzip_sp.jpg 2x,
						<?php echo get_template_directory_uri(); ?>/images/index/sp/gzip_sp@2x.jpg 3x"
				sizes="92vw">
		<source srcset="<?php echo get_template_directory_uri(); ?>/images/index/gzip_pc.jpg"
				sizes="46vw">
		<img src="<?php echo get_template_directory_uri(); ?>/images/index/gzip_pc.jpg" alt="" width="1200" height="644">
	</picture>
</div>

<picture>タグは複数の画像から最適な一枚のみを表示することができ、不要な画像は読み込まないので無駄なトラフィックを発生させないという利点があります。

背景画像の場合 ※SCSS形式

@mixin mq_sp {
	@media (max-width:767px){
		@content;
	}
}
@mixin retina3x {
	@media only screen and (-webkit-min-device-pixel-ratio: 3),(min-resolution: 3dppx) {
		@content;
	}
}

.main_head {
	height: 700px;
	background: url(images/index/main01.jpg) center top no-repeat;
	background-size: cover;
	@include mq_sp {
		height: size_sp(650);
		background: url(images/index/sp/main01.jpg) center top no-repeat;
		background-size: cover;
	}
	@include retina3x {
		background: url(images/index/sp/main01@2x.jpg) center top no-repeat;
		background-size: cover;
	}
	(以下略)

なぜこの解像度で切り替えるのか

端末と解像度の一覧
端末名 ピクセル Density デバイスピクセル
iPhone5/5s/SE 320 2.0 640
iPhone6/7/8 375 2.0 750
iPhone6~8 Plus 414 3.0 1242
iPhoneX/XS 375 3.0 1125
iPad 768 2.0 1536
iPad Pro 1024 2.0 2048

横幅いっぱいの背景画像を表示する場合
・Density1~2のスマホ → スマホ用の基本となる画像を横幅750pxで作成すればDensity2でデバイスピクセルが最大のiPhone6~8でそのまま表示してもぼやけない。
・Density3のスマホ → iPhoneXでも横幅1500pxあれば余る。今後もっと高解像度の新型が出ても当分は大丈夫。
・タブレット  →  PC用を使い回せばいい