Cover Image for PageSpeed Insights で携帯パフォーマンススコアを満点 (100) にした

PageSpeed Insights で携帯パフォーマンススコアを満点 (100) にした

実験
AVIF
LCP
PageSpeed Insights
srcset
TBC

はじめに

この Webサイトは Next.jsVercel にデプロイして公開しています。また、SvelteKit でも同じ外観で実験用の非公開(正確には公開しているが、検索エンジンには登録していない)サイトを作成しています。こちらは Cloudflare にデプロイしています。

Next.js + Vercel の画像最適化は良く出来ています。画像最適化を考慮しないで作ってもかなり良いパフォーマンスが出ます。SvelteKit の場合は、公式ドキュメントで画像最適化方法を色々教えてくれますが、どの方法で行うかを検討して実装する必要があります。

実験用の Webサイトを PageSpeed Insights でパフォーマンス計測したところ、携帯のパフォーマンススコアが 80点台でした。この Webサイトでは、画像最適化をやっていなかったので、色々試してみて 100点を出しました。実際に行った作業と、その過程で知った情報を記事にしてみました。

実際に行った作業は、SvelteKit 固有の技術に依存しないので、汎用的に応用できる内容だと思っています。

パフォーマンスについて

パフォーマンス(ここではページの応答速度という意味です)は重要ですが、この記事では、どこまでパフォーマンスを上げるのが良いかという観点はとりあえず置いといて、実験として純粋に携帯スコアで 100点を出すのを目指します。パフォーマンスの指標は、筆者が良く利用している「PageSpeed Insights」を利用します。

PageSpeed Insight は、携帯(スマホ)と PC を分けた 2種類のスコアを出してくれます。PC の方は比較的簡単に良いスコアを出せますが、携帯の場合は通信速度などが遅いため、良いスコアを出すのが難しいように思います。

評価環境について

筆者の実験用サイトは静的なページなので、パフォーマンス的に有利な SSG (Static Site Generation) にしています。参考までに、SSG について分かりやすいと思うページを貼っておきます。

og-image
SPA, SSR, SSGって結局なんなんだっけ?
https://zenn.dev/rinda_1994/articles/e6d8e3150b312d#ssg

デプロイしている環境(実行環境)は、Cloudflare Pages です。これは「サーバーレスのフルスタック開発プラットフォーム」です。サーバーレスなのでサーバーの保守をする必要がありません。いわゆるエッジコンピューティング (ここでは CDN と同じような意味) として動作するのでパフォーマンス的にも有利です。

og-image
フル スタックアプリケーション
Cloudflare Pagesをは、フロントエンドエンジニア向けフルスタックアプリケーションで、コードを簡単にデプロイできます。試してみませんか?
https://www.cloudflare.com/ja-jp/developer-platform/pages/

SvelteKit、Cloudflare Pages どちらもパフォーマンスを重視しています。サイトを構築する土台が高速なのでパフォーマンススコアの改善作業には良い環境だと思います。ただ、「はじめに」も書きましたが、画像最適化を行っていなかったのでパフォーマンススコアを確認しながら実験してみました。

最初のパフォーマンス測定

まずは現状のパフォーマンスを測定してみます。

左側が携帯(スマホ)で、右側が PC の結果です。携帯(左画像)のパフォーマンススコアは 81 です。スコアを悪くしている原因は、赤字で表示されている Largest Contentful Paint 5.2 秒 です。

LCP (Largest Contentful Paint) とは、ビューポート内で描画された最大のコンテンツ要素(具体的には「睡蓮」の画像)の表示に要した時間を示しています。

LCP の画像ファイルは jpg で、画像サイズは 4608 x 2592、ファイルサイズは 204.1 KB です。回線速度の速い PC では 1.2 秒なのに対して、回線速度の遅い携帯では 5.2秒となっています。

PageSpeed Insights の計測値は結構ばらつく場合があります。特に、TBT (Total Blocking Time) は大きく変動する場合があります。後ほど TBT についてもチューニングを行うのですが、とりあえず LCP に着目したいので、上記の計測結果では TBT の小さいものを使っています。

画像ファイルを avif にしてファイルサイズを小さくする

画像ファイルサイズを小さくすることで LCP を改善します。次世代画像フォーマットとして webp, avif がメジャーだと思います。これらは ファイルサイズを小さくするのに最適な画像フォーマットです。筆者がお勧めするのは avif です。avif の参考サイトを貼っておきます。

og-image
Webサイトの画像フォーマットは積極的に「AVIF」を使おう
https://zenn.dev/xx_suzuki/articles/sharp-verification

画像フォーマット毎のファイルサイズは次のようになりました。

画像ファイル(フォーマット)ファイルサイズ(KB)
ec-wordpress-tailwind.jpg204.1
ec-wordpress-tailwind.webp131.1
ec-wordpress-tailwind.avif45.9

jpg, webp, avif どれも画像品質パラメータを設定できます。筆者は目視で劣化の具合を確認して画像変換していて、主観として問題ないレベルの品質は確保しています。avif は jpg の 1/4 以下のサイズとなりました。とても優秀だと思います。(画像サイズはそのままです。念のため)

それではパフォーマンス測定してみましょう。

携帯の LCP が 5.2秒から 2.9秒に改善されて、パフォーマンススコアも 81 から 94 と良くなりました。しかし、目標の 100点満点は出ていません。PC については十分なパフォーマンスが出ています。

srcset を使って最適な画像サイズのファイルを配信する

見出しの通りなのですが srcset について、参考になるサイトを貼っておきます。

og-image
srcsetとsizesが理解できなかった人のために、日本一分かりやすく解説してみた - Qiita
レスポンシブイメージとは画面幅や端末(パソコン、スマホなど)に応じて表示するイメージを切り替えることなぜ重要なのかスマホみたいな小さな画面で表示する時に5000x2500みたいな巨大画像を送り…
https://qiita.com/dowanna6/items/b9e132b4c56e67491027

PC のディスプレイよりスマホのディスプレイの方が小さいから、小さい画像サイズのファイルで良いというのは誤りです。ディスプレイには解像度が色々有って、PC の場合は 1920 x 1080 あたりが多いと思われますが、スマホの場合は機種によって大きく異なり 1520 x 720 ~ 3840 x 1644(4kスマホ)といった解像度であり、一般的な PC よりむしろ高い場合もあるでしょう。

筆者がこのブログサイトを立ち上げた当初、アイキャッチ画像は 1280 x 720 で作っていました。これだと、4k対応のディスプレイを使用している方だと性能を発揮できません。そこで最近はなるべく解像度の高いものをアイキャッチにしています。

srcset で指定するサイズは、Next.js が画像最適化で自動生成する値をお手本にして評価用の実装をしました。(実験と割り切って、ファイル名は決め打ちという荒業です。)

<img
  loading="eager" fetchpriority="high"
  sizes="100vw"
  srcset="https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-640.avif 640w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-750.avif 750w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-828.avif 828w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-1080.avif 1080w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-1200.avif 1200w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-1920.avif 1920w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-2048.avif 2048w,
    https://storage.googleapis.com/ys-notebook-public/ec-wordpress-tailwind-3804.avif 3804w"
.....
/>

上のコードのように、画像は Google Strage から取得しています。設定で変わると思いますが、かなり速いという印象です。実際に運用するケースでは、異なる画像サイズのファイルを手作業で作るというのは手間がかかるので現実的でないでしょう。自動で作るようにプログラムするとか。そこで、画像処理サービス imgix も試してみました。これは便利で、画像 URL に横幅などのパラメータを付与すると(例えば w=640)処理済みの画像を返してくれます。同じ画像はキャッシュされるので、初回は遅くても2回目以降にキャッシュがヒットすれば高速なレスポンスを期待できます。しかし、実際に使って Google Strage と比較すると、Google の方が速い結果となりました。パフォーマンススコア (LCP) を改善できないので、今回は imgix を使わない判断をしました。(筆者の使い方に問題がある可能性も有るので、参考までの情報としてください。)

画像サイズの異なる 8つの avif ファイルを作成します。筆者は、sharp-cli という node.js で動く画像変換ツールを利用して作成しました。Linux のコマンドラインで次のように使います。resize パラメータに横幅を指定します。

sharp -i ec-wordpress-tailwind.avif -o ec-wordpress-tailwind-1080.avif resize 1080

og-image
sharp-cli
CLI for sharp.. Latest version: 5.1.0, last published: 3 days ago. Start using sharp-cli in your project by running `npm i sharp ...
https://www.npmjs.com/package/sharp-cli

PageSpeed Insights にリンクのあったドキュメント「適切なサイズの画像」に「RespImageLint は、画像の最適な srcset 値と sizes 値を特定するための便利なブックマークレットです」という記述があったので試してみました。実行結果は次のキャプチャ画像のとおりです。

RespImageLint

適切な sizes の値を教えてくれて、とても便利です。教えてもらった sizes の値を設定してテストをパスしました。

それでは、パフォーマンス測定してみましょう。(以下、携帯のキャプチャ画像だけにします。PC は既に満点なので省略します)

pmps-f3-k-1

LCP が 2.9秒から 1.8秒に改善してスコアは 99 と惜しいところまで来ました。ただ、これは数回実行した時の一番良いスコアです。同じ条件なのにスコア変動が大きい。あまり良くないスコアのキャプチャは以下になります。

pmps-f3-k-2

LCP はあまり変わりませんが、TBT (Total Blocking Time) が 380 ミリ秒と赤字で表示されています。TBT が足を引っ張って良いスコアが出ていないのです。

TBT (Total Blocking Time) を改善する

現状、画像ファイルは Google Strage から持って来ます。これを自身のサイトから配信すると少し速くなります。Cloudflare Pages が CDN のようなものですし、同一サイトに画像があればネットワーク接続を再利用するため、別のドメインへのネットワーク接続の時間が不要となります。(実際試していますが、0.2秒前後速くなる感じです)

しかし、先ほどの結果から今は LCP よりも TBT を改善すべきだと分かったので分析してみましょう。

PC版 Chrome の Web開発ツールを使います。PageSpeed Insights の携帯でのネットワーク速度を設定します。筆者は、ネットワーク スロットリング プロファイルにカスタムプロファイルを追加しました。

Web開発ツールでパフォーマンス測定した結果は次になります。

ネットワークを見ると、フォントファイルの転送(緑色のバー)が目に付きます。フレームを見るとピンク色のレイアウトが長いですね。恐らく、レイアウトはフォントのダウンロードが終わるのを待っていて(ブロックされている)、フォントのダウンロードが終わってレイアウトが確定してからペイント(描画)を始めていると読めます。

Next.js ではどうなっているのか調べると

フォント(緑色 bbb233… のバー)は真っ先に読み込んでいます。

フォントを早い段階で読み込むのが重要なのは間違いないでしょう。そこで、ヘッダーにフォント先読みのコードを追加します。

vi src/app.html
(赤字の部分を1行挿入します。SvelteKitの場合 app.html を編集します。)
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%sveltekit.assets%/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="robots" content="noindex">
    <link rel="preload" href="/fonts/noto-serif-jp-v21-latin-regular.woff2" as="font" crossorigin="" type="font/woff2">
(以下省略)

それでは、PageSpeed Insights で計測してみましょう。TBT は結構変動するのですが、良いスコアを出したキャプチャは次のようになりました。

pmps-f5-k-1

TBT が0ミリ秒ですからフォント先読みは正解です。スコアは 99 で今一歩満点には及びません。そこで、先ほどは見送った画像を自身のドメインから配信するようにしてみます。srcset を次のように変更します。

srcset="/ec-wordpress-tailwind-640.avif 640w,
        /ec-wordpress-tailwind-750.avif 750w,
        /ec-wordpress-tailwind-828.avif 828w,
        /ec-wordpress-tailwind-1080.avif 1080w,
        /ec-wordpress-tailwind-1200.avif 1200w,
        /ec-wordpress-tailwind-1920.avif 1920w,
        /ec-wordpress-tailwind-2048.avif 2048w,
        /ec-wordpress-tailwind-3804.avif 3804w"

パフォーマンス測定してみると、大体 98~99 のスコアでした。原因を分析してみると、表示範囲外の画像ファイルが最適化できていないのが悪いと推論しました。そこで、表示範囲外の画像に対しても 自身のドメインから配信するように修正しました。パフォーマンス測定の結果を次に示します。

pmps-f5-k-2

目的の携帯パフォーマンススコア 100 を達成しました!!繰り返してみると TBT の値が安定しないのですが、高確率でスコア 100 が出ます。

結構、長文になってしまい説明不足な部分も有ったと思いますが、最後まで読んでくれてありがとうございます。この記事が少しでもパフォーマンスチューニングの参考になれば幸いです。

参考:筆者が使用した画像ツール

参考までに、この記事を書くにあたり使用した画像ツールを簡単に紹介します。全て avif 対応です。

GIMP

画像ツール PhotoShop は有名でプロの方は当たり前に使用していると思います。ただし、比較的高価なので、たまにチョット使う場合は躊躇するのではないでしょうか?そんな方にお勧めなのが GIMP です。機能的には PhotoShop と同じように使えるフリーツールです。使いこなすのは若干難しいかもしれないのが難点ですが、ネットで調べたりすれば大抵わかります。

og-image
GIMP
GIMP - The GNU Image Manipulation Program: The Free and Open Source Image Editor
https://www.gimp.org/

Squoosh

直感的に使いやすい画像フォーマット変換ツールです。ブラウザで動作するので、アプリのインストールが不要ですぐに使えます。変換前後の画像確認がスライドバーで動かしながら確認できるなど、お手軽で良いです。

sharp-cli

この記事の本文でも紹介しています。node.js 上で動作する 画像変換ツールです。node が動く環境がないと使えないので一般向けではありませんが、シェルスクリプトなどと併用すれば、大量の画像ファイルを一括変換したりできるので便利です。CLI でない sharp パッケージも有ります。こちらは JavaScript などのコーディングで利用できます。そのリンクを貼っておきます。

og-image
sharp
High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images. Latest versi ...
https://www.npmjs.com/package/sharp

【おまけ】本記事のアイキャッチ

(今回のアイキャッチも例によって記事内容とは何の関係もありません)

最近、急に夏らしくなったので夏の風物詩的な何かを考えた時に、麦わら帽子を連想しました。

今回も写真素材をフリーで使える PhotoAC さんを見ていたら、猫が麦わら帽子をかぶるという面白い写真を見付けました。この猫は、なかなか良い表情をしていると思いませんか?


More Stories

Cover Image for 高品質なスロー静止画アニメーションプログラム(html カスタム要素)を作ってみた

高品質なスロー静止画アニメーションプログラム(html カスタム要素)を作ってみた

NEXT.js
SvelteKit
WordPress
実験
animation
drawImage
requestAnimationFrame

静止画(主に写真を想定)がゆっくりと移動する落ち着いたアニメーションプログラム(html カスタム要素)を作ってみました。静止画(写真)を利用して、手軽にアニメーションできます。高品質な静止画(写真)を高品質なまま、『カクカクしないで滑らかに』アニメーションします。

Cover Image for WordPress で Tailwind CSS を使う方法

WordPress で Tailwind CSS を使う方法

WordPress
Tailwind CSS

WordPress で Tailwind CSS を使う方法 3種類を具体的に説明しています。「Tailwind CDN を使う方法」「プラグインを使う方法」「Tailwind CLI を使う方法」の 3種類です。