😇

画像の最適化のTips集

2021/09/27に公開

画像の最適化する方法を色々とまとめました。
パフォーマンスに関して特に詳しいというわけではないので、これはそうじゃないよ!!やもっといい方法あるよ!!などがありましたら、コメントで教えてください!!

画像の最適化の目的

そもそもなぜ、画像を最適化する必要があるのでしょうか?

それは、基本的にはサイトのパフォーマンスを向上させるためでしょう。
ここでいう、パフォーマンスの向上とは、ページ読み込み速度やレンダリング速度、ユーザーによる操作に対する反応速度などのサイトの速度を速くすること、です。

なぜ、このパフォーマンスを向上させることが重要なのかは、以下の記事に詳しく書いてあるので一部抜粋します。

https://developer.mozilla.org/ja/docs/Learn/Performance/why_web_performance

サイトのダウンロードとレンダリング時間を短縮することで、コンバージョン率とユーザー維持率が向上します。

コンバージョン率とは、サイト訪問者が測定された、または希望するアクションを実行する率のことです。例えば、購入する、記事を読む、ニュースレターを購読するなどです。コンバージョン率として測定されるアクションは、ウェブサイトのビジネス目標によって異なります。

パフォーマンスはコンバージョンに影響を与えます。サイト訪問者は、サイトが 2 秒以内に読み込まれることを期待していますが、モバイルではそれ以下になることもあります (一般的にはもっと時間がかかる)。同じサイト訪問者でも、遅いサイトを 3 秒で放棄し始めます。

サイトの読み込み速度は 1 つの要因です。サイトがユーザーの操作に反応するのが遅かったり、不愉快に見えたりすると、サイト訪問者は興味を失い、信頼を失います。

パフォーマンスは、優れたユーザー体験には不可欠なのです。

画像の最適化のTips

シンプルな画像には、SVGを使用する

JPEGやPNGやWebPはラスタ形式(ビットマップ画像形式)に対して、SVGはベクター形式です。
ラスタ形式は拡大するとぼやけてしまうので、複数のサイズの画像を用意する必要が出てしまいますが、ベクター形式は、品質を損なうことなく任意の大きさでも表示することが出来るので一枚あれば十分です。ですので、可能ならSVGの画像を使用することをおススメします。

ただ、写真のような複雑な画像の場合は、SVGで表現しようとすると逆に容量が大きくなったり不自然な表示になることがあるので、その場合にJPEGやPNGやWebPなどを使用してください。

ラスタ形式なら、WebPを使用する

WebPは、JPEGやPNGよりもファイルサイズが小さく、より多くの機能を備えた新しい画像フォーマットです。

WebPについては、以下の記事が詳しいのでご参照ください。
https://web.dev/serve-images-webp/

記事の一部を抜粋します。

WebP images are smaller than their JPEG and PNG counterparts—usually on the magnitude of a 25–35% reduction in filesize. This decreases page sizes and improves performance.

YouTube found that switching to WebP thumbnails resulted in 10% faster page loads.
Facebook experienced a 25-35% filesize savings for JPEGs and an 80% filesize savings for PNGs when they switched to using WebP.
WebP is an excellent replacement for JPEG, PNG, and GIF images. In addition, WebP offers both lossless and lossy compression. In lossless compression no data is lost. Lossy compression reduces file size, but at the expense of possibly reducing image quality.

DeepL翻訳様によると、

WebP画像は、JPEGやPNGに比べてファイルサイズが小さく、通常、25~35%程度の削減が可能です。これにより、ページサイズが小さくなり、パフォーマンスが向上します。

YouTubeでは、サムネイルをWebPに変更したところ、ページの読み込みが10%速くなりました。
Facebookでは、WebPへの切り替えにより、JPEGのファイルサイズが25〜35%、PNGのファイルサイズが80%削減されました。
WebPは、JPEG、PNG、GIF画像の優れた代替手段です。また、WebPには可逆圧縮と非可逆圧縮があります。可逆圧縮では、データは失われません。非可逆圧縮では、ファイルサイズを小さくすることができますが、その分、画質が低下する可能性があります。

ですので、パフォーマンスの観点からはJPEGやPNGよりも、WebPを使用することをオススメします。

画像を圧縮する

圧縮していない画像には不要なバイトが含まれており、それがファイルサイズを肥大させます。
適切に圧縮すれば見た目はほぼ全く変わりませんので、圧縮しましょう!

圧縮をする方法は色々ありますが、ここではおススメのWEBツール「TinyPNG」を紹介します。
https://tinypng.com/

TinyPNGという名前ですが、PNGだけではなく、JPEGやWebPも圧縮することが出来ます。
試しに、TinyPNGのトップをスクリーンショットで撮った画像を圧縮しました。

圧縮前(932.1 KB)
TinyPNGのスクリーンショット

圧縮後(238.4 KB)
TinyPNGのスクリーンショット

圧縮前と圧縮後を比べてみてどうでしょうか?ファイルサイズは74%も削減していますが、見た目はほとんど変わっていないと思います。

設定も不要で簡単ですので、ぜひ使ってみてください!

レスポンシブ画像を使用する

ラスタ画像を様々なサイズで表示する場合、複数のサイズの画像を用意する必要があります。なぜなら、小さい画像を大きく表示するとぼやけてしまうし、大きな画像を小さく表示するのはデータ量がもったいないからです。

理想的には、複数のサイズの画像が利用可能で、デバイスのサイズに応じて適切なサイズの画像を提供することです。これを、可能にするのがレスポンシブ画像なのです。

通常のimg要素は以下のようなもので、画像ファイルを一つしか指定できません。

<img src="cat-lg.jpg">

それに対して、レスポンシブ画像は、以下のように複数のサイズのファイルを指定することが出来ます。

<img srcset="cat-sm.jpg 640w,
             cat-lg.jpg 1280w" 
     sizes="(max-width: 960px) 640px,
            1280px"
     src="cat-lg.jpg">

ここで出てきたsizessrcset属性については、下記の記事に分かりやすく説明してあるので、抜粋させていただきます。

sizes

その画像をどのサイズで表示したいのか指定します。目的はこれだけです。
次で説明しますが、srcset 属性で、w 単位を使った時のみ記述します。
メディアクエリーの条件毎に、複数の値を指定することもできます(max-width や min-width を使って場合分けする)。
通常はレイアウトが変化するブレークポイント(となるビューポートの幅)で条件を分けることが多いでしょう。
ブラウザは 1つ目の条件から見ていって最初に合致したものを採用します。
例えば、sizes="(max-width: 767px) 70vw, (max-width: 991px) 350px, 500px" の場合、ビューポート幅が767px以下なら 70vw、991px以下なら 350px、それ以外なら 500px となります。
メディアクエリーで場合分けする場合は、width属性を指定してはいけません。width属性を指定すると、画像サイズが指定した値に固定されてしまい、場合分けされないからです。
指定するサイズの単位は、px, em, vw などいろいろ使えます。但し、% は使えないです。

srcset

Webブラウザに対して、実際に使える画像の候補を伝えます(サイズ違いの画像、正確にはピクセル密度記述子が異なる画像)。
「画像ファイルへのURL」と「そのファイルのサイズ(幅)」のペアを複数指定することができます。
「ファイルのサイズ(幅)」は、「x 単位」と「w 単位」のどちらかで指定します。
Webブラウザは、sizes 属性によって決定されたサイズで画像を表示するために、srcset 属性で指定された画像の中から最適なものを選んでダウンロード・表示してくれます。
基本的には、用意しているサイズ違いの画像を羅列するだけです。あとは勝手に Webブラウザが選んでくれます。

https://laboradian.com/img-srcset-sizes/

ブラウザが画像を読み込む流れを確認してみましょう。

  1. まず、デバイスの表示されてる幅を見る
  2. sizesのリストの中のどのメディアクエリーの条件が合致したかを確認
  3. その条件に指定されているサイズを選択
  4. 選択したサイズに最も近いsrcsetのリストで参照される画像を読み込む

レスポンシブ画像を実現する方法にpictureタグを使用する方法もあります。そちらにつきましては、下記のページをご参照ください。
https://developer.mozilla.org/ja/docs/Web/HTML/Element/picture

画像のサイズを指定する

パフォーマンスにはいくつかの指標があるのですが、その一つにCLS(Cumulative Layout Shift)という指標があります。CLSとは、こちらの記事によると

Cumulative Layout Shift (累積レイアウト シフト数、CLS) は、視覚的な安定性を測定するための重要なユーザーを中心とした指標です。これは、ユーザーが予期しないレイアウト シフトに遭遇する頻度の数値化に役立つ指標であり、CLS が低ければ低いほど、そのページが快適であることが保証されます。

とのことです。要するに、ページのコンテンツが突然移動して別の場所をタップしてしまった経験があると思いますが、そういうレイアウトのシフトがどの程度あるのかを測定したのがCLSなのです。

そのCLSが悪化する要因はいくつかあるのですが、その一つがサイズが指定されていない画像によるものです。

画像にサイズを指定していないと、画像の読み込み時にすでに表示されていたコンテンツの位置がずれてしまいます。下記のコードのように、画像にサイズ属性であるwidthheightを指定すると、初期段階で画像のスペースを確保されるようになり、画像の読み込み時の位置のずれが軽減されます。

<img width="600" height="400">

レスポンシブ画像の際などサイズが変わる場合、widthheightをどう指定するべきなのでしょうか?
ここで重要なのは、画像のアスペクト比です。画像のアスペクト比とは、画像の横幅と縦幅の比率のことを指します。画像のアスペクト比が分かると、片方のサイズが分かればもう片方のサイズが分かるようになります。例えば、アスペクト比が3:2の場合、

  • 画像の横幅が600pxの場合、縦幅は 600×(2/3) = 400px となります。
  • 画像の縦幅が400pxの場合、横幅は 400×(3/2) = 600px となります。

ブラウザはwidthとheight属性に基づいて、画像のデフォルトのアスペクト比を設定します。重要なのはアスペクト比なので、レスポンシブ画像でサイズが変わる場合も元の画像のサイズでもいいですし、他のサイズでもアスペクト比が変わらないければ問題ないです。

読み込みを遅延させる

通常、最初のページロード時に一斉に画像が読み込まれます。これは、ページの読み込み速度に影響しますので、できるだけ最初に読み込まれる画像を減らした方が読み込む速度が速くなります。
多くの画像は画面外にあり最初に読み込む必要はありませんので、その画面外の画像の読み込みを遅延させることで、読み込みへの影響を軽減させます。

画像の読み込みを遅延させる方法も色々あるのですが、ここでは比較的新しい方法を紹介します。

imgタグに以下のようにloading属性を付加することで、遅延読み込みを実現することが出来ます。

<img loading="lazy">

2020年から、このloading 属性が標準仕様になったようです。各種ブラウザの対応状況に関しては、こちらに最新の情報があります。まだ、Safariでは対応していませんが、サポートしていないブラウザでも、副作用もなく単に無視されるだけなので、気にせず使用することが出来ます。

loading属性でサポートされている値は、現在以下の二つです。

lazy: 画像の読み込みを、ビューポートから計算された距離に達するまで遅延します。
eager: 画像がページのどこにあるかに関わらず、すぐに読み込みます。

まとめ

まとめです。

  • シンプルな画像には、SVGを使用する
  • ラスタ形式なら、WebPを使用する
  • 画像を圧縮する
  • レスポンシブ画像を使用する
  • 画像のサイズを指定する
  • 読み込みを遅延させる

以上のことを意識して開発すると、パフォーマンスがかなり改善するはずです!!

参考

https://developer.mozilla.org/ja/docs/Learn/Performance

https://developer.mozilla.org/ja/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images

https://web.dev/fast/

https://web.dev/serve-images-webp/

https://web.dev/cls/

Discussion