PageSpeed Insights スコア改善:「改善できる項目」編
目次
2018年11月にGoogleのPageSpeed Insights(PSI)が大幅リニューアルされた。LightHouseという今までChrome拡張などのオプションでしかなかったツールが標準導入され、チェック項目や採点の仕方が大きく変わったが、この対策についての情報が少なかったので、今回請け負った静的HTMLサイトの高速化で行なったことを記録に残しておきます。
改善可能性
実際に改善できる項目
・次世代フォーマットでの画像の配信
・オフスクリーン画像の遅延読み込み
・効率的な画像フォーマット
・キーリクエストのプリロード
・CSS の最小化
・JavaScript の最小化
・テキスト圧縮の有効化
・静的なアセットと効率的なキャッシュポリシーの配信
・複数のページ リダイレクトの回避
ある程度の改善が可能な項目
・適切なサイズの画像
・レンダリングを妨げるリソースの除外
・ウェブフォント読み込み中の全テキスト表示
実際は改善が難しい項目
・使用していない CSS を削除してください
・JavaScriptの実行にかかる時間の低減
・過大なネットワーク ペイロードの回避
・メインスレッド処理の最小化
・過大な DOM サイズの回避
・サーバー応答時間の短縮(TTFB)
次世代フォーマットでの画像の配信
jpg, jpeg, pngではなくGoogleが開発した新しいWebp形式の画像を表示するようにすればOK。
このWebp形式自体は数年前からあるが、現在ではChrome以外のブラウザ(Safariなど)では非対応らしい。そのためhtaccessの記述などでjpe?g/pngとwebpを対応非対応で出し分ける必要がある。
コードは「webp htaccess」などでググれば多く出回っている。 https://doocts.com/3288https://qiita.com/miyanaga/items/6570c3c9ae8e15dbb57c
今回の案件ではWordPressではなく静的なHTMLで記述したページの高速化だったので、先のリンクを参考にEWWW OptimizerでWebp形式に変換した画像をダウンロードし、それをサーバーにアップロード、2番目の参考リンクのhtaccessのコードを記述して、PSI上は警告が消えた(本当にChromeなどの対応ブラウザでWebp画像が読み込まれているかはChrome Developer ToolのNetworkタブを開いてページを再読み込みし、typeの列にwebpと表示されるかどうかで確認できる)。
CDNを使っている場合
CloudflareなどのCDNサービスを使っている場合は注意が必要。Webpに対応したブラウザのユーザーがアクセスしてきたときにWebPの画像をキャッシュし、次にWebp非対応ブラウザ(iPhoneのブラウザはほぼ非対応)のユーザーがアクセスしてきた時に、CDNサービスはキャッシュ済みのWebP画像を渡してしまう。結果、ユーザーに画像が表示されなくなってしまう。
この時のhtacessの書き方は割愛する。
WordPressでEWWW Image Optimizer を使っている場合は以下の項目にチェックを入れるだけで良しなに対応してくれるよう。
追記
以下のWebサービスでも問題なく画像をwebpに変換してくれ、PSIの警告消えました。 https://lab.syncer.jp/Tool/Webp-Converter/
オフスクリーン画像の遅延読み込み
いわゆるLazyLoadで、一般的にはjQuery依存のLazyLoadライブラリが定番らしいが、調べるなかでjQueryに依存しないlazysizesライブラリの方が軽くて記述も簡単だったので、今回これを採用した。 https://wemo.tech/207
しかしサイト上部でslick.js(jQuery依存のスライドショーのライブラリ)を使用していたので、ファーストビューのスライド部分では上手く遅延読み込みがでませんでした。これはslick.jsに元々備わっている画像遅延機能を使ってsrc=""
をlazy-data=""
に置き換えることで解決した。
途中、echo.jsを使おうかとも思い試してみたが、lazysizesに比べて画像のカクツキ(スクロール時の読み込み開始タイミングやスピードの遅さ)がひどかったので、やはりlazysizesがベストだと思う。
WordPressの場合
WordPressであれば LazyLoad by WP Rocket プラグインがおすすめ。他と比べてカスタムフィールドで出力した画像や関連記事のサムネイル画像などのあらゆる画像遅延ができ、ロード時のチラつきも気にならない。標準のthreshold
(スクロールが画像の何ピクセル上まできたら画像読み込みを開始するかの閾値)の設定が綺麗なのだろう。
ただしファーストビューに入る画像のうち、本文以外のロゴやサイドバーの画像まで遅延させてしまうので、これらをdata-no-lazy='1'
の付与によって無効化しなければならないのが少しやっかい(functions.phpにてクラスの指定による除外フィルターの設定も出来るが、複数のクラスを指定する方法がどうにも分からなかったので1つずつimg
タグに属性付与していくしか今のところ方法が分からない)。
レンダリングを妨げるリソースの除外
これはこれまでもあった「レンダリングブロックしている(HTMLの描画を妨げている)CSSやJavaScriptを後から読み込ませる」もの。
WordPressならAutoptimizeや Scrpit To Footer プラグインなどで対応できるが、今回は静的なHTMLサイトなのでプラグインは使えない。
JavaScript
まずは<script>
タグを</body>
タグの直前に1個ずつ手動で移動させた。
またjQuery以外のscriptには非同期かつ順序読み込みのdefer
属性をつけて遅延させた(async
属性だと同じ非同期でも読み込み順序が記述した順番通りになる保証はなく、それぞれのscriptが読み込み終わり次第バラバラに実行されて不具合の原因になる。しかしなぜかGoogleはasync
を推奨している)。
jQueryは重要なスクリプトライブラリ(Critical Request Chainとか言うらしい)なので、初めに呼ばないとナビメニューやスライドショーが動かなくなったりする。よってこれの読み込み部分はheadの中に留めておいた方が無難(つまりjQueryによるレンダリングブロックは諦める)。一応<head>
の中ではなく</body>
直前で呼べばエラーもなくPSIの警告も消えるらしいが、それで不具合が本当に起きないかは自信がない。結局「jQueryを利用しているライブラリやJavaScripコードを読み込むより先にjQuery本体を読み込むこと」を理解していることが大事である。
CSS
cssは<head>
の中から<footer>
や</body>
の直前に移動するだけではレンダリングブロックは解除できない。
こちらのブログを参考にCSSを非同期で読み込ませるscriptを </body>
の直前に書いて対処するのがいいよう。
<script>
(function(d){
var s = d.getElementsByTagName('script')[0];
var c1 = d.createElement('link');
c1.rel = 'stylesheet';
c1.href = 'http://ホスト名/CSSファイルを置いてあるパス/style.css';
s.parentNode.insertBefore(c1, s);
var c2 = d.createElement('link');
c2.rel = 'stylesheet';
c2.href = '//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css';
s.parentNode.insertBefore(c2, s);
})(document);
</script>
// 引用元: takkaaaaaの日記
cssはhead内で読みことが推奨されているため、footer内に<link>
タグを記述するのは不適切らしい。なのでfooterにて上記のscriptを走らせ、s.parentNode.insertBefore(c1, s);
でページの最初に読み込まれているscript(基本head内にあるはず)の前に読み込みをさせている。
ただ全てのCSSの読み込みを遅くすると一瞬見た目が酷く崩れて表示されてしまうので、ファーストビューに必要なCSSだけ<head>
の中などに<style>
タグでインライン化して書き出す必要がある。
ちなみにCSSとJavaScriptをインライン化する際はもちろん圧縮(改行やタブ、コメントを削除)する方がよく、これには便利なWebサービスがあるのでこちらを利用すべし。
https://prettydiff.com/?m=beautify
使われているCSSが分からない場合
Chrome Developer Toolで要素選択して適用クラスを見ていくしかないかも。
「現在のページで使われているCSSの抽出」であれば、同じくChrome Developer ToolのCoverage機能(Toolのタブに見当たらなければ[…]
をクリックしてでるMore Tool?の中に入っている)で洗い出せる(このCoverageの使い方も詳しい記事が少なかったのでコメントいただければ書きます)。
WordPressの場合
WordPressの場合、CSSはAutoptimizeプラグインで遅延読み込みすればよい。ただし基本的には読み込み時に一瞬表示崩れが起きるので、その場合はAutoptimizeで最適化&AggregateされたCSSだけがレンダリングブロックした状態になったところで良しとしている。
JavaScriptは Scripts To Footer プラグインが使えたはずだし、functions.phpに遅延読み込みのコードを直接書いてもよい。ただしjQueryなどの「先に読み込まないとエラーが出るファイル」はレンダリングブロックしてでも先に読み込むしかない。
ただWordPress純正のwp-includesに入っているjQueryよりも、Google CDN から読み込むようにした方が早くなるはず。
// GoogleCDN から jQuery を読み込む
add_action('wp_print_scripts','my_deregister_script',100);
function my_deregister_script() {
if (!is_admin()) {
wp_deregister_script('jquery');
wp_enqueue_script('jquery','https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js',array(),'1.12.4');
}
}
適切なサイズの画像
モバイルの場合は画面幅が大きいiPhoneXS Maxでも414px(414×896ポイント)なので、それ以上の大きさの画像はバイト数を無駄に使っていることになる。 https://qiita.com/TD3P/items/b3b754bde584abc98f44
これもMacでサイズを変更した(iPadも考慮し750pxの横幅とした)上で再度webp形式の画像に変換しアップロードし、事なきを得た。 こちらのリンクも参考になります。 https://pantograph.co.jp/blog/research/above-the-fold.html
WordPressの場合
WordPressであればバージョン4.4くらいからレスポンシブイメージと言って画像を挿入したときに画面サイズごとにw300
のような属性?が割り当てられたimgタグが自動で用意・挿入されるようになり、基本はこのレスポンシブイメージ機能によりこの項目は自動でクリアされるはず。
しかしテーマによってはこれを無効にしていたり、上手く機能しない場合もあるようで、そう言った時は手動でリサイズするしかなさそう。
しかしこの時はPCとモバイルでページが分かれており、そのうちのモバイル専用ページだったので良かったが、PC/モバイル兼用のページだと414px以上の画像もPCで必要なので、どうやってやればいいんだろう…。@media
とdisplay
プロパティで出しわけとかするしかないのだろうか。今一度、参考リンクや本で勉強し直す必要がありそうです。
キーリクエストのプリロード
これはGoogleの公式ドキュメントが分かりやすいが、要は「jsなどを<link>で読み込んだ時、それらのコードの中でもjsファイルを読込む必要があると、親のHTML→子のjs→孫のjsという順番で読み込まれて遅いので、「HTMLの<head>の段階で明示的に孫のjsを(preloadを指定して)事前に読み込んでおきましょう」ってことです。 https://developers.google.com/web/tools/lighthouse/audits/preload
ちなみに、色んなブログなどの情報をみて誤解しやすいのは「HTML(親)の<head>
で元からある<link>
にrel="preload"
をつけるんじゃなくて、その<link>
で読んだjsファイル(子)で使うためのjsファイル(孫)を、子から呼び出されるより先に親の段階で以下のように<head>
に読み込みlinkを追記して事前読み込みしましょう」ってことですからね。
<!-- parent.html -->
<head>
<link rel="preload" as="script" href="grandchild-script.js"> <!-- ここを追記しようぜってこと -->
<link as="script" href="child-script.js">
</head>
またフォントの場合は書き方が異なり、以下のように書くとのこと(ちなみにHTMLの記述ルールでは"(ダブルクォーテーション)はあってもなくてもいいみたいです)。
<link rel="preload" as="font" type="font/woff2" href="font.woff2" crossorigin>
もろもろの参考はこちらです。 https://blog.jxck.io/entries/2016-03-04/preload.html
WordPressでフォントをpreloadする例
CSSの場合が分かりにくかったので例を追記。WordPressではテーマのstyle.cssなどで以下のようにフォントを指定している。
@font-face {
font-family: "slick";
src: url('/wp-content/themes/sentry-void-master/fonts/slick.eot?1547954276');
src: url('/wp-content/themes/sentry-void-master/fonts/slick.eot?&1547954276#iefix') format("embedded-opentype"), url('/wp-content/themes/sentry-void-master/fonts/slick.woff?1547954276') format("woff"), url('/wp-content/themes/sentry-void-master/fonts/slick.ttf?1547954276') format("truetype"), url('/wp-content/themes/sentry-void-master/fonts/slick.svg?1547954276#slick') format("svg");
font-weight: normal;
font-style: normal;
}
この場合、フォントファミリーslick
が適用されたHTMLテキストの読み込みが始まるまで上記ソースURLのフォントの読み込みは始まらないので遅くなる。そこで以下のように「テーマのheader.phpの<head>
タグの中に以下のコードを記述しましょうよ」ということですね。
<link rel="preload" as="font" type="font/woff" href="/wp-content/themes/sentry-void-master/fonts/slick.woff?1547954276" crossorigin>
まとめ
上記で「改善できる項目」に出ていた警告は消えましたが、たまに「サーバーの応答時間が遅い(TTFB)」という項目がでて2秒くらい表示が遅れてると言われたり、他の「診断」などの項目が赤や黄色の警告のままなので、そこを改善しないと90以上のスコアを取るのは難しいようです。
続き:「診断編」へ
診断編も書きました。診断と言えど「静的なアセットと効率的なキャッシュポリシーの配信」などの項目でスコアは大きく変わるので、こちらもご参考ください。
PageSpeed Insights リニューアル後のスピード改善で実施したこと(診断編)