🖼️

解像度とフォーマット対応状況の両方に配慮してWebP画像やAVIF画像を扱う

2024/06/24に公開

こんにちは、Webサイト作ってますか? Webサイトを作っていると、Lighthouseスコアを上げるために画像のサイズやフォーマットにも気を配りたくなりますよね。

筆者は画像のフォーマットにはあまり頓着してこなかったので、「フラットな画像ならPNG」「込み入ったイラストはJPEG」「なんかWebPとかいうのもあるらしいけどよくわからん」くらいの解像度で適当に使っていました。しかし、最近の開発でLighthouseスコアのチューニングをしてみたところ、色々新しい知見が溜まったので、自分用の備忘録として残しておこうと思います。

3行まとめ

  • ちゃんと複数の解像度の画像を用意しようね
  • WebPやAVIFといった次世代フォーマットも使ってみようね
  • <picture><source> は便利

画像のサイズを複数用意する

表示するディスプレイの解像度に合わせて、表示する画像の大きさを調整することで、Retinaなディスプレイでもそうでないディスプレイでも画像がきれいに表示されるようになります。例えば、/images/sample.jpg という画像を表示する場合、/images/sample.jpg/images/sample@2x.jpg という2つの画像を用意しておいて、Retinaディスプレイの場合は @2x のほうを、そうでない場合は無印のほうを表示する、といった設定は、次のように書きます。

<img
  src="/images/sample.jpg"
  srcset="/images/sample.jpg 1x, /images/sample@2x.jpg 2x"
>

デフォルトの表示は src 属性に書きつつ、 srcset 属性でディスプレイの解像度に応じた画像を指定します。これにより、取得しにいく画像の解像度が切り替わります。便利ですね。

WebPもAVIFも良さそうやん

画像のフォーマットにも目を向けてみると、WebPやAVIFといったフォーマットに切り替えた方がいい場面も多くあります。Lighthouseでいうと、「次世代フォーマットでの画像の配信」という項目で指摘されるやつですね。

次世代フォーマットでの画像の配信
次世代フォーマットでの画像の配信

これは実質「WebPとかAVIFくらいは使いなよ〜」というやつです。

WebPはなんだかんだで登場してから長いので、なんとなくは存在は知っていました。本記事の本筋ではないので、詳細は省きます。これ読んでください。

https://developers.google.com/speed/webp?hl=ja

cwebp コマンドで気軽に変換できるので、用意するのも簡単でした。

一方、最近まで恥ずかしながら全く知らなかったのがAVIFです。AVIF(AV1 Image File Format)はHEIF技術をベースにしたフォーマットで、iPhoneなどで使われているHEICの親戚に当たるものです。圧縮効率が高く、軽量で高画質な画像を提供できるということで、最近のブラウザで対応が進んでいます。

https://aomediacodec.github.io/av1-avif/

次の記事を読むと、AVIFについて色々と検証されていて興味深いです。

https://zenn.dev/xx_suzuki/articles/sharp-verification

また、caniuseを見てみると、2024年6月現在、主要ブラウザでは対応が済んでいるみたいですね。

AVIFの対応状況
AVIFの対応状況

AVIFへの変換には、僕はたまたま見つけたsquooshを使っています。

https://squoosh.app/

オープンフォーマットということもあって、いろんな選択肢がありそうですね。

もともと1.4MBあったJPEG画像をsquooshでAVIF変換してみたのですが、次のような結果になりました。

  • Quality 50%(ほぼ画質に遜色なし)→ 114kB
  • Quality 30%(やや粗くなる)→ 57.3kB

Quelity 30%で元の3%までサイズが減った
Quelity 30%で元の3%までサイズが減った

実用上はQuality 50%で綺麗すぎるくらいなので、これでいいかなと思っています。

AVIFやWebPを使う

というわけで、画像のフォーマットも切り替えてみましょう。画像の表示には<picture>要素を使います。<picture>要素は、複数の画像ソースを指定して、ブラウザが対応しているものを選んで表示することができます。

<picture>
  <source type="image/avif" srcset="/images/sample.avif">
  <source type="image/webp" srcset="/images/sample.webp">
  <img src="/images/sample.jpg" alt="サンプル画像">
</picture>

<source>要素でtype属性にフォーマットを指定し、srcset属性に画像のパスを指定します。上から順にブラウザの対応しているものがあれば採用し、もしなければ<img>要素のsrc属性で指定した画像を表示します。

解像度にも対応させたい場合は、次のように書きます。

<picture>
  <source
    type="image/avif"
    srcset="/images/sample.avif 1x, /images/sample@2x.avif 2x"
  >
  <source
    type="image/webp"
    srcset="/images/sample.webp 1x, /images/sample@2x.webp 2x"
  >
  <img
    src="/images/sample.jpg"
    srcset="/images/sample.jpg 1x, /images/sample@2x.jpg 2x"
  >
</picture>

これで、解像度に合わせて、かつブラウザの対応しているフォーマットで画像を表示することができます。

まとめ

適切な画像を表示できるようチューニングするには、なんらかのロジックを通さないといけないとは思っていたのですが、かなりの部分がHTMLのみの表現で実現できることがわかり、嬉しくなって記事を書いてしまいました。

source要素には、メディアクエリーで条件付けができる media 属性などもあり、さらに複雑な条件で画像を切り替えることもできるようです。

よりよいWeb表現のために、精進していきます。

株式会社モニクル

Discussion