モバイルウェブのスピードアップに不可欠なのは 画像・JS・フォント の最適化 #ChromeDevSummit

[レベル: 中級]

昨日おとといに続いて、今日も Chrome Dev Summit 2018 のセッションレポートをお届けします。

セッションのタイトルは “Speed Essentials: Key Techniques for Fast Websites” です。
昨日レポートしたセッションと同じようにモバイルウェブの高速化がテーマです。
しかし、こちらはより実践的な内容になっています。
パフォーマンス改善に非常に役立つテクニックが満載です。

Kate Hempenius talking at Chrome Dev Summit 2018

パフォーマンス改善の優先対象は画像とJS、フォントの3つ

モバイルウェブで 1 ページあたりデータ量が多いリソースは次の順番(HTTP Archive 調べ)

  1. 画像 (約 500 KB)
  2. JavaScript (約 380 KB)
  3. フォント (約 80 KB)

モバイルウェブで 1 ページあたりデータ量が多いリソース

この 3 つは Performance Budget(パフォーマンス バジェット)においても、最も考慮すべき要因になっている。

画像

画像はパフォーマンス最適化で一番重要。最適化できていないサイトが実に多い。

画像を最適化する手段には次のようなものがある。

  • 適切なフォーマット
  • 適切な圧縮
  • 適切なサイズ・密集度
  • 必要なときだけ読み込む (Lazy-load)

これらの施策は、時間と労力を削減するために自動化してシステム的に実行すべき。

画像フォーマット

画像のフォーマットは目的に応じて選択する。

アニメーション GIF

アニメーション GIF はサイズが大きいので、MPEG-4 (MP4) を使う――アニメーション GIF は MP 4 の 5 〜 20 倍サイズが大きくなる(実は Twitter では、アニメーション GIF をアップロードすると MP 4 に自動的に変換されている)

たとえば、ffmeg を使うとコマンドラインでアニメーション GIF を MP 4 に変換できる。
$ ffmeg -i dog.gif

変換後は HTML タグを <img> タグから <video> タグに更新する。

<video autoplay loop muted playsinline>
    <source src="dog.mp4" type="video/mp4"> 
</video>

MP 4 動画をアニメーション GIF のように、自動再生・ループ再生・消音・インライン再生にするために autoplay loop muted playsinline を追加するといい。

WebP

WebP は、Chrome だけがサポートしている画像フォーマットではもはやなくなった。グローバルで 72 %のユーザーが利用できる。
[鈴木補足: WebP は Google が開発した、品質を保ったまま高圧縮できる画像フォーマット。]

  • Chrome: サポート
  • MS Edge: サポート
  • Firefox: サポート予定 [※鈴木補足: バージョン 65 からか?]
  • Safari: ?

WebP は JPEG や PNG に比べると、25〜35 % サイズが小さくなる。The Tribune(インドのニュースサイト)では、WebP のサポート後、ページの読み込み時間が 30 %改善した。

WebP をサポートするブラウザとしないブラウザの両方に適切に画像を配信するように HTML タグを記述できる。

<picture>
    <source type="image/webp" srcset="flowwer.webp"> ⬅ WebP
    <source type="image/jpeg" srcset="flowwer.jpg"> ⬅ JPG
    <img src="flower.jpg">
</picture>

ブラウザが WebP をサポートしていれば WebP を読み込むし、サポートしていなければ JPG を読み込む。上から順番に、サポートしているフォーマットの画像を 1 つだけ読み込む。img タグは、picture/srcset をサポートしていない古いブラウザ向け。

動画フォーマット

将来的には、新しい動画フォーマットの AV 1 を推奨する。

AV1 の圧縮:

  • VP 9 (WebM) よりも 約 30 % 優れている
  • x264 (MPEG-4) よりも 45 〜50 %優れている

デスクトップ版 Chrome 70 で AV1 をサポートするようになった。

画像圧縮

画像の圧縮には 2 種類ある。

  • Lossless: データを損失しない
  • Lossy: データを失うが、より高い圧縮が可能

Lossless 圧縮 vs. Lossy 圧縮

少なくとも Lossless で圧縮するべき。ほとんどのサイトにとっては、より高圧縮するために Lossy を使うのもいい。

Lossy 圧縮は、0 〜 100 のスケールで圧縮率を設定できる。ゼロに近づくほど高圧縮。ただし画像のクオリティも落ちる。

Lossy 圧縮 と画像品質

ほとんどの画像では、80 〜 85 で圧縮すれば、ファイルサイズを 30 〜 40 % 削減しつつ、クオリティの劣化は最低限に抑えられる。

圧縮ツールは、Imagemin がポピュラー。webpack や node.js、gulp などさまざまな技術から利用できる。JPG や PNG、GIF など主だった画像フォーマットのプラグインがある。

画像のサイズ

すべてのデバイスに対して同じ大きさの画像を配信するのではなく、デバイスのスクリーンサイズに合わせた大きさの画像を配信する。データの転送量を抑えられるだけではなく、CPU の使用も抑えられる。

ほとんどのサイトでは、3 〜 5 種類のサイズの画像を準備しておくといい。Instagram は実際にそうしている。複数サイズの画像を配信することで、Instagram は 平均して 20 % ほどデータの転送量を削減できた。

画像サイズ変更のツールとして、npmパッケージの次を利用できる。

  • Sharp
  • Jimp

複数のサイズの画像を配信するときの HTML タグ:
<img scrset="flower-small.jpg 480w, flower-large.jpg 1080w" sizes="50vw" src="flower.jpg">

px ではなく、w を使う(1行目)。
srcsetsizes によって画像の大きさを示すことで、どの画像をダウンロードすべきかをブラウザが決定できる。

Lazy Loading

Lazy Loading/Lazyload は必要になるまでリソースの読み込みを遅らせる技術。画像によく使われるが、ほかのリソース、たとえば JavaScript にも利用できる。Lazyload は最初の読み込みのパフォーマンスを上げることができる。

またすぐに使用しないリソースをダウンロードしないので、データ転送量を抑えることもできる。

Spotify は Lazyload を有効に使っている。ページの表示とともにそのページにあるすべての画像を読み込んだとすると 18 MB になる。Lazyload を使ってスクリーンに入る画像だけを読み込ませると 1 MBに減る。

Lazyload は JavaScript で実装するのが一般的。しかし、Chrome がブラウザの機能として Lazyload をネイティブサポートするようになる。サードパーティ製のスクリプトは不要。

[※鈴木補足] Chrome の Lazyload ネイティブサポートに関してはこちらの記事を参照

フォント

外部からダウンロードするウェブフォントもスピードを遅くする要因になる。

Flash of Invisible Text (FOIT) と呼ぶ現象がある。ブラウザがウェブフォントを読み込むまで、文字が現れない。

FOIT はユーザー体験が悪いので、Flash of Unstyled Text (FOUT) を採用するといい。FOUT では、ブラウザがウェブフォントをダウンロードするまで、システムフォント(PC やスマホに入っているフォント)を代わりに使って文字を表示する。文字はブラウザにすぐに表示される。ウェブフォントのダウンロードが完了すると、システムフォントと置き換わる。

FOUT は簡単に実装できる。

@font-face {
	font-family: 'Pacifico';
	src: url (...pacifico.woff22) format ('woff2');
	font-display: swap;
}

最後の行がフォントを入れ替えるようにブラウザに命令する部分。

JavaScript

画像とフォントと並んで、JavaScript もウェブでダウンロードされるデータ量の上位に入るリソース。JavaScript の 1ページあたりのデータの中央値は、モバイルで 370KB、デスクトップで 420KB。JavaScript は圧縮されて転送されるので実際には 1MBほどのサイズのファイル。それを元に戻して、パースして、実行するとなると性能の低いデバイスでは非常に遅くなる。

JavaScript が使われる場がますます増えてきているので、JavaScript の高速化が必要。

JavaScript の最適化には次のような施策が効果的。

  • Code Splitting
  • Preload
  • 利用しない CSS/JS の調査

UNIQLO 事例

UNIQLO Canada は JavaScript の最適化で高速化に成功した。

UNIQLO がやったこと:

  • Code Splitting
  • Performance Budget
  • etc.

成果:

  • Time to Interactive: 2 秒 ⬇
  • 直帰率: 14 % ⬇
  • 滞在時間: 31% ⬆
  • セッションあたりの PV: 25 % ⬆

UNIQLO 成功事例

UNIQLO 成功事例

成果に関してはほかの要因も関係しているだろうが、パフォーマンス向上が大きく貢献していることは確か。

以上です。

JavaScript の最適化に関しては、端折っています(僕は開発者ではないので、コーディングの部分を適切に解説できない気がするため😥)。
セッションの録画が YouTube にアップロードされているので詳しく知りたい方は視聴してください(12:27 あたりから JavaScript のパートが始まります)。

一方、画像の最適化は技術にさほど詳しくなくても実行できることが多かったはずです。
画像は改善の余地が最も多く、難易度が比較的低いにもかかわらず効果が大きいのが特徴です。
できることからさっそく試してみましょう。