🌭

コーダーができるサイトの高速化10選

2023/06/15に公開
1

はじめに

この記事では「コーダーが対応できるサイトの表示速度向上」についての具体的な手法を紹介していきます。

サイトの表示速度はユーザー体験を大きく左右し、サイトの種類によってはUI(サイトの見た目)より重要視される場合もあります。

2017年にはGoogleが「ページの読み込み速度によって離脱率が変わる」と発表しました。

・1〜3秒の離脱率:32%
・1〜5秒の離脱率:90%
・1〜6秒の離脱率:106%
・1〜10秒の離脱率:123%
引用:https://www.thinkwithgoogle.com/

このようにサイトの表示速度はとても重要な指標になります。

サイトの表示速度向上には様々な手法が存在して、効果が出やすいものもあれば出にくいものもあり、実際に本番反映してみないと結果が分からないものもあります。また、難易度や実務上で許可を貰いやすいかなども考えなくてはいけません。

これらを踏まえ、効果が出やすく、対応もしやすい方法から順番に解説していきます。

サイトの表示速度の計測方法

サイトの表示速度やパフォーマンスを計測するにはGoogleが提供する「PageSpeed Insights(ページスピードインサイト)」を使います。

PageSpeed Insightsは、Webバージョンとデベロッパーツールバージョンがあります。

Webバージョンでは、PageSpeed InsightsにアクセスしてURLを入力するだけで使えます。

デベロッパーツールバージョンでは、デベロッパーツールを開いて要素やコンソールなどのタブメニューに「Lighthouse」という項目があるので、そこから使えます。

サイトの表示速度の決まり方

具体的な表示速度向上の解説の前に、まずはどのようにサイトの表示速度が決まるかを簡単に解説していきます。

フロントエンド側で表示速度に影響を与える指標は主に4つあります。

  • サーバーへの「リクエスト回数」
  • サーバーへの「リクエストサイズ」
  • サーバーへの「リクエストタイミング」
  • HTMLパースの「速度」

1つ目の「リクエスト回数」とは、CSSや画像などのファイルをサーバーからダウンロードする回数のことです。ダウンロードの回数が多ければ多いほど、つまり、サイトに読み込んでいるファイル数が多いほどサイトの表示に時間がかかります。 なので、読み込むファイル数を減らすことで表示速度が向上します。


リクエスト回数のイメージ図

2つ目の「リクエストサイズ」とは、サーバーからダウンロードしてくるファイルなどのサイズのことです。ファイルサイズが大きいほどサイトの表示に時間がかかります。 なので、ファイルサイズを小さく(圧縮)することで表示速度が向上します。


リクエストサイズのイメージ図

3つ目の「リクエストタイミング」とは、サーバーからファイルをダウンロードするタイミングのことです。通常、サイトを訪れたタイミングで全てのファイルを読み込みます。それに対して、画面外の画像の読み込みを遅らせるなど、リクエストのタイミングをズラすことでサイトを訪れたタイミングのダウンロード量(リクエストの回数やサイズ)を減らせます。 このように画像などのファイルの読み込みをズラすことを「遅延読み込み」や「非同期読み込み」と言います。


リクエストタイミングのイメージ図

4つ目の「HTMLパースの速度」とは、ブラウザがHTMLファイルを解析してDOMツリーを作成する速さのことです。解析中にファイル(CSS、JavaScript、画像など)が見つかると、ダウンロードが終わるまで解析はストップします。つまり、ファイルのリクエスト回数やサイズが大きいほどHTMLパースの完了が遅くなります。

https://coliss.com/articles/build-websites/operation/work/how-the-browser-renders-a-web-page.html

https://zenn.dev/ak/articles/c28fa3a9ba7edb#全体の流れ

なので、これまでに解説した1〜3を改善することで4のHTMLパースの速度が速くなり、その結果、サイトの表示速度が速くなります。

1. 画像の圧縮

一番手軽で、かつ一番効果が出やすいのが画像の圧縮です。

サイト容量の半分以上は画像が占めています。画像のサイズを圧縮することで、リクエストサイズを小さくできます。

画像の圧縮には外部サービスを使うのが一般的だと思います。

https://tinypng.com/

https://www.iloveimg.com/ja/compress-image

他にも、GulpやWebpackを使った方法もあります。これらの良いところは、ローカル環境で完結し、ファイル名やフォルダ構造をそのままの状態で圧縮できる点です。外部サービスにアップロードする方法に限界が来たら、これらの方法を試してみるのもいいと思います。

https://ics.media/entry/220204/

https://www.asobou.co.jp/blog/web/gulp-imagemin

画像の圧縮も重要ですが、適切な拡張子を使うことも重要です。写真ならjpg、ベタ塗りや透過ならpng、ベクターならsvgなど、画像に適した拡張子を使うことも意識してみてください。

また、画像の圧縮率や拡張子によっては画像がぼやける場合もあるので、状況に応じてうまく対処できるようにしましょう。

2. 画像の遅延読み込み(loading="lazy")

画像まわりでもう一つ効果が出やすいのが、画像の遅延読み込みです。遅延読み込みをすることで、ページ読み込み時のリクエスト回数とリクエストサイズを減らすことができます。

imgのloading属性を使うことで、ブラウザが画像を表示する必要があるまで(例えば、ビューポート内に画像が入るまで)読み込み(ダウンロード)を遅らせることができます。

ひとつ例を紹介すると、ページ読み込み時のスクロール位置がファーストビューの場合、それより下に配置している画像はページ読み込み時の段階では見えないので読み込まれず、スクロールして画面内に表示されそうになったら画像が読み込まれます。

デベロッパーツールの「ネットワーク」タブを開いた状態で、loading="lazy"を使ったサイトを見てみるとイメージが湧きやすいと思います。スクロールしていくとどんどん画像が読み込まれていくはずです。

具体的な書き方は以下のようになります。

<img
  src="path/to/img.png" alt=""
  width="600" height="300"
  loading="lazy" decoding="async"
/>

loading="lazy"を付けることで遅延読み込みになります。また、decoding="async"を付けることで画像のデコードを非同期化します。これらを使うにはwidthheightは必須になります。

loading="lazy"decoding="async"どちらも付けると、loading="lazy"が優先されます。ファーストビューの画像にはdecoding="async"を、それ以降の画像にはloading="lazy"を付けるのが良いです。

ファーストビューの画像もloading="lazy"にしてしまうと、本来真っ先に読み込みたい画像なのに読み込みが遅れてしまうので、画像の表示にタイムラグが生じてしまいます。

これらの属性は正しく扱わないと画像が表示された時の見え方がおかしくなったりするので、正しく理解してから使うようにしましょう。

2023/7/20追記

decoding属性の私の解釈は少し違っていたみたいです。画像のデコードが完了しなくても、その下のHTMLは読み込まれるみたいです。

decoding属性に関してはキテレツさんの記事でとても詳しく解説されているので是非読んでみてください。

https://zenn.dev/ixkaito/articles/deep-dive-into-decoding

3. 読み込んでいるファイルを見直す

CSSやJavaScriptなど読み込ませるファイルを減らせば、リクエスト回数とリクエストサイズを減らすことができます。

何年も運用しているサイトの場合、使っていないファイルを読み込んでいることが多いので、改修する際に見直してみましょう。

また、外部プラグインは保存したファイルを読み込ませるのではなく、キャッシュを利用できるCDN(Content Delivery Network)で読み込ませるのがおすすめです。

https://news.mynavi.jp/techplus/article/zerojavascript-15/

CSSやJavaScriptのファイルをひとつにまとめるのも効果的です。意識するべき点を以下にまとめました。

  • CSS
    • @importは使わず、ひとつのファイルに全てのスタイルを記述する
    • Sassを使ってスタイルをひとつのファイルにまとめる
  • JavaScript
    • ひとつのファイルに全てのJavaScriptの処理を記述する
    • GulpやWebpack(Babel)を使ってJavaScriptの処理をひとつのファイルにまとめる
    • ライブラリは外部ファイルとしてではなくnpmで読み込む

4. <script>タグにdefer属性を付与する(非同期化)

<script>タグにdefer属性を付与することで、HTMLパースを止めずにJavaScriptを読み込ませることができます。それにより、HTMLパースが通常より速く完了します。

<script src="path/to/script.js" defer>

defer属性に関する解説はこちらの記事がとても分かりやすいので是非読んでみてください。

https://qiita.com/phanect/items/82c85ea4b8f9c373d684

また、HTMLファイルを読み込んでからブラウザに表示されるまでの仕組みを理解することも重要です。これらを正しく理解できれば適切な方法でサイト高速化を行えるようになります。

https://qiita.com/tanaShoe/items/f2d8f3d2ae034a094f99

5. JavaScriptの処理を見直す

ページ読み込み時に実行されるJavaScriptの処理を見直すことで、HTMLパースが速くなります。

見直すポイントをいくつか挙げてみたので、リファクタリング(コードの見直し)の参考にしてみてください。

  • 同じ要素を何度も取得していないか
  • 繰り返し使われる値を何度もベタ書きしていないか
    • 💡何度も使う値は変数化する
  • 繰り返し使われたり、似たような処理を何度もベタ書きしていないか
    • 💡繰り返し使われたり、似たような処理は関数化する
  • ページ読み込み時に必要ない処理も実行していないか
    • 💡ページ読み込み時に必要な処理のみを実行されるようにする
  • 大量のデータに対してfor文などの繰り返し処理を行っていないか
    • 💡他に方法がないか検討する
  • 特定の処理が終わったタイミングで他の処理を実行させるときに、setTimeout()で◯秒後に実行...のようにしていないか
    • 💡async/awaitやPromiseを使う
  • スクロール量に応じた処理を実装する時にscrollイベントを使っていないか(表示速度改善というよりはページパフォーマンス向上の観点になります)

6. 画面幅に応じて画像を切り替えるときは<picture>タグを使う

画面幅に応じて画像を切り替えるときは、display: noneで表示を切り替えるのではなく、<picture>タグを使います。

display: noneで切り替える場合、表示されるのは片方の画像だけでも両方の画像が読み込まれているので、その分無駄な読み込みが発生しています。

Bad...
<img class="pc" src="path/to/pc.png">
<img class="sp" src="path/to/sp.png">
Good!
<picture>
  <source srcset="path/to/md.png" media="(min-width: 768px)">
  <img src="path/to/sm.png">
</picture>

https://b-risk.jp/blog/2022/09/picture-srcset/#picture_source

7. 画面幅に応じて画像の解像度を変える

MacやiPhoneなどの高解像度(Retina)ディスプレイで画像をキレイに表示するには表示サイズの倍の解像度が必要になるので、その分ファイルサイズが大きくなってしまいます。

srcset属性を使うことで、解像度(デバイスピクセル比)に応じた画像の切り替えが可能になり、リクエストサイズを減らせます。

<img
  srcset="path/to/sm.jpg 640w, path/to/md.jpg 767w, path/to/lg.jpg 1080w"
  src="path/to/lg.jpg"
  sizes="(max-width:1080px) 100vw, 1080px"
/>

こちらの記事で詳しい使い方が解説されているので参考にしてみてください。

https://ics.media/entry/13324/#レスポンシブイメージにおける画像出し分け

srcset属性を使うには、1枚の画像に対して複数の解像度の画像が必要で、これを自分で用意するのはかなり大変です。

ほとんどの場合、プラグインを導入したりツールで一括生成したりしているので、srcset属性を使う際は「各解像度の画像をどうやって用意するか」も検討する必要があります。

8. CSSファイルの非同期化

CSSファイルのサイズが膨大な場合、レンダリングブロックが発生してブラウザに描画されるまでの時間が長くなってしまいます。

https://www.1-firststep.com/archives/9806

<link>タグにmedia="print" onload="this.media='all'"を追加することで、CSSが非同期読み込みになりレンダリングがブロックされなくなります。

<link
  rel="stylesheet" href="path/to/style.css"
  media="print" onload="this.media='all'"
>

https://qiita.com/rana_kualu/items/95a7adf8420ea2b9f657

この方法を行うと、ページ読み込み時に一瞬だけスタイルが当たらずレイアウトが崩れている状態でブラウザに表示される場合があります。なので、ページ読み込み時に見える部分(メインビジュアルなど)のCSSは<head>の中に<style>でインラインで読み込ませたりなど工夫が必要です。

また、コアウェブバイタルの「CLS」の指標が著しく悪くなるケースもあるので、メリット・デメリットを正しく理解したうえで実行するようにしましょう。

9. iframeの遅延読み込み

iframeも画像と同様に遅延読み込みが可能です。

<iframe src="https://example.com"
        loading="lazy"
        width="600"
        height="400"></iframe>

https://web.dev/i18n/ja/iframe-lazy-loading/

10. その他の施策

これまでに解説した内容の他にも表示速度改善の施策はたくさんあります。しかし、ひとつずつ解説していたら膨大な量になってしまうので、残りは箇条書きベースで簡単に紹介していこうと思います。

おわり

サイトの表示速度に影響を与えるのは画像が大半です。 この記事で紹介した内容も9個中4個(10番目は除く)は画像に関することです。なので、画像はちゃんと圧縮する、正しい拡張子を使う、適切な大きさにする、遅延読み込みをする、だけでかなり変わるはずです。

他にはファイル読み込みに関する内容も多かったと思います。当たり前のことですが、意外とできていないのが「不要なファイルは読み込まない」です。サイトの歴史が長くなればなるほど不要なファイルは増えていきます。これらとうまく付き合うのも表示速度向上のポイントのひとつです。

今回紹介した内容(特に1〜9)を対応してもサイトの表示速度が変わらない場合、利用しているフレームワーク(WordPressやJSライブラリ)の書き方や大元に問題があったり、サーバーサイドに何らかの原因があると考えられます。

聞き慣れない用語も多かったと思うので、用語の意味を調べながらこの記事を読んでもらうとより深く理解できると思います。

ネクスキャット テックブログ

Discussion

tommy34tommy34

これらの手法を適用するとリクエストがどのくらい早くなるのでしょうか