share facebook facebook facebook twitter twitter menu hatena pocket slack

2021.08.18 WED

コアウェブバイタルを意識したフロントエンド改善レポート vol.2

こんにちは。アイレットデザイン事業部のマークアップ/フロントエンドエンジニアの工藤です。アイレットデザイン事業部ではINSIDE UI/UXと題して、所属デザイナーとエンジニアがデザイン・SEO・アクセシビリティ・UI/UXなどそれぞれスペシャリティのある領域に対する知見を幅広く発信しています。今回は前回記事の続編としてコアウェブバイタルを意識した画像の実装方法について書いていきたいと思います!

画像は不可欠。だが重い…


印象に残るデザインのウェブサイトを作るためには画像が欠かせません。
そしてHTML上でimg要素を用いて画像を表示すること自体はとても簡単です。

<img src="sample.jpg" alt="画像" />

しかし、画像はテキストファイルに比べるとファイルサイズが大きいため、実装を工夫しないとパフォーマンスに悪影響を及ぼしページがもっさりと重くなります。

ではコアウェブバイタルの観点で考えたとき、どう画像の実装を工夫すれば良いでしょうか?

LCP観点で見る改善ポイント

画像でコアウェブバイタル指標のLCP (Largest Contentful Paint) を意識するポイントは以下の通りです。

  1. ヒーローイメージ(メイン画像)を先行読み込み(preload)する
  2. srcset属性を使い、マルチデバイスに対応する※
  3. 不必要に高精細な画像を使わず、圧縮・最適化を行う※

※2、3はLCPだけを改善するわけではなくLCPに限らず画像実装全般に影響がある施策です。

LCPはLargest Contentful Paintの正式名称が示唆する通り、いわゆるファーストビューでの最大のコンテンツ要素(画像またはテキスト)が表示されるタイミング(=レンダリング完了するタイミング)を測定する指標です。

テキストではなく画像が最大のコンテンツ要素となる場合には、ヒーローイメージの読み込み速度がLCPに大きく影響するということですね。
そこで先ほどのシンプルなimg要素の実装をちょっとずつ調整します。

ヒーローイメージ(メイン画像)を先行読み込み(preload)する

head内にlink要素を使ってLCPとなるヒーローイメージ(メイン画像)の先行読み込み(preload)をlink rel="preload" as="image"として指定すれば、ブラウザはその画像を早期にレンダリングし高速表示します。

<head>
  <link rel="preload" as="image" href="hero.jpg">
</head>

media属性(メディアクエリ)、imagesrcset属性、imagesizes属性を使えばさまざまなデバイスサイズや解像度に対し、レスポンシブイメージ対応もできます。

<!--これもOK!-->
<link rel="preload" as="image"
      href=“hero_sp.jpg”
      media="(max-width: 768px)">
<link rel="preload" as="image"
      href=“hero_pc.jpg” media="(min-width: 769px)">
<!--これもOK!-->
<link rel="preload" as="image"
      href="hero.jpg"
      imagesrcset="
        hero_400px.jpg 400w,
        hero_800px.jpg 800w,
        hero_1600px.jpg 1600w"
      imagesizes="50vw">

background-imageの先行読み込み(preload)

なおLCPとなるヒーローイメージがbackground-imageである場合も、background-imageとして指定されている画像をlink rel="preload" as="image"で指定してやればOKです。

rel=”preload” についてもっと詳しい記事はrel=”preload” によるコンテンツの先読みをご覧ください。

Lighthouse v6.5以降、監査項目 “Preload Largest Contentful Paint image” が含まれるようになり、LCPとなる画像の先行読み込みの有無が厳格にチェックされるようになりました。
ただpreloadをあまりにも多くのリソースに対して指定すると、今度は逆に遅延の原因になるとのことで注意です。

画像でLCPを改善するポイントは以上となります!LCPは他にもCSSやJSの読み込みや通信プロトコルのHTTP2化などで改善させることができますが、今回の記事では割愛し次回以降の記事で書いていく予定です。

srcset属性を使い、マルチデバイスに対応する

<img src="sample.jpg" 
     srcset="sample@2x.jpg 2x, 
     sample@3x.jpg 3x" 
     alt="画像" />

img要素内でsrcset属性を記述するとRetinaディスプレイ/高解像度ディスプレイに対応した画像を置けます。このテクニックをレスポンシブイメージまたはレスポンシブ画像と言います。「レスポンシブデザイン」と語感が似ていますが異なる概念なので注意です。

アートディレクション

以下のようにpicture要素とimg要素を組み合わせれば、ディスプレイサイズと解像度…などさまざまな条件別にそれぞれ異なる画像を出し分けることができます。これをアートディレクションと呼びます。たとえばPCの時は横長の大きな画像、スマホでは縦長の小さな画像…というように出し分けができて便利です。

<picture>
  <source media="(max-width: 799px)"
          srcset="sample-sp.jpg 1x, sample-sp@2x.jpg 2x, sample-sp@3x.jpg 3x">
  <source media="(min-width: 800px)"
          srcset="sample-pc.jpg 1x, sample-pc@2x.jpg 2x, sample-pc@3x.jpg 3x">
  <img src="sample.jpg" alt="画像">
</picture>

iretコーポレートサイトでも、スマートフォンサイズでは縦長、タブレット以上のサイズでは横長の画像を出しわけています。

レスポンシブ画像とアートディレクションについてのより詳しい記事は下記がおすすめです。
レスポンシブ画像 – MDN Web Docs

不必要に高精細な画像を使わず、圧縮・最適化をする

今回は画像圧縮にはimagemingulp-imageminを使用しました。
その結果、例えば3倍解像度のメイン画像は4.4mbから1.4mbにファイルサイズを削減できました。

圧縮前の画像ファイル

圧縮後の画像ファイル。見た目は同じだがファイルサイズが削減されている

タスクランナーや黒い画面を使用せずとも、オンライン画像圧縮サービスのsqooshtinypng を使って手軽に画像圧縮することもできます。ただしこうしたオンラインサービスを使用する際はそのリスクを理解しましょう。
またWordPressユーザーならプラグインを利用してみるのも良いでしょう。

WebP

またGoogleが開発した画像形式であるWebP(ウェッピー)はjpegやpngなど従来の形式よりも画像ファイルサイズを軽量にできます。実装においては前述のアートディレクションと同様の方法で自動的に表示を切り替えます。

<picture>
  <source type="image/webp"
          srcset="sample.webp">
  <img src="sample.png"
       alt="画像">
</picture>

ただしIEは2021年7月現在のところWebP非対応、またSafariはSafari14以降がWebP対応であり、実装においては注意が必要です。

FIDを改善するポイント

次にコアウェブバイタル指標の2つ目、FID (First Input Delay) を意識するポイントですが、FIDはFirst Input Delayの正式名称が表す通り、ユーザーが最初にページを操作(リンクをクリックしたり、ボタンをタップするなど)してからブラウザーが実際にイベントハンドラーの処理を開始できるようになるまでの時間を測定します。

LighthouseとPageSpeed Insightsの開発者であるAddy Osmani氏はページ読み込み時に画像がその他の重要なリソースの読み込みの邪魔になり、帯域が飽和するとFIDに影響があるとしており、メインスレッドのCPU使用率を減らすことでFIDを改善できるとしています。
参照: HOW DO IMAGES IMPACT USER EXPERIENCE AND THE CORE WEB VITALS?

ということは先ほど紹介したレスポンシブイメージ化や画像の圧縮はFIDにも多少影響するという理解で良さそう。
ただしFID改善にはJavaScriptの実装やリソース配信のHTTP2化なども関わってくるので、「画像」というスコープだけでは考えないほうが良いのはありますね。

FID改善についてもっと詳しい記事はこちらをご覧ください。

CLSを改善するポイント

最後に画像でコアウェブバイタル指標の3つ目、CLS (Cumulative Layout Shift) を意識するポイントは
1. width/height属性を記述する
2. CSSプロパティaspect-ratioを利用する

となります。

webページにアクセスしてテキストを読んでいたら、後から表示された画像やiframe要素によってテキストがガタッと押し下げられる不快なあの現象…時にはそのせいで意図せず広告をクリックしてしまったり😭…みなさんも経験があると思います。このページ表示の後からレイアウトがガタッとずれる現象はレイアウトシフトと呼ばれており、その量を計測するコアウェブバイタル指標がCLS (Cumulative Layout Shift) です。Addy Osmani氏が解説するこの動画の3分31秒あたりからCLSのデモをご覧いただけます。

width/height属性を記述する

ではどうやってレイアウトシフトを防げばいいのでしょうか?
img要素にwidth/height属性を記述すると、このレイアウトシフトが起きなくなります。簡単ですね!

<img src="sample.jpg" alt="画像" width="640" height="360" />

従来width / height属性にはピクセル単位のサイズを記入していましたが、HTML Living Standardによる仕様変更によりアスペクト比を記入できるようになりました(2019年10月より標準化)。width/height属性に数字のみを入れ単位をつけないのがポイントです。

レスポンシブ対応が必要な場合、CSSで下記のように画像の高さが固定値(たとえば360px)にならないようheight="auto"を指定すれば大抵の場合大丈夫です。

img {
  height: auto;
  width: 100%;
}

CSSプロパティaspect-ratioを利用する

ではimg要素に直接width / height属性を記述できない時はどうすればいいでしょうか。この場合はCSSプロパティaspect-ratioを使ってみましょう。

img {
  width="100%"
  aspect-ratio: 16 / 9;
}

このように指定してやれば、ブラウザがレイアウト計算を行う際に16:9の比率…つまり640px:360pxなどとレスポンシブに可変する画像のためのスペース(プレースホルダー)を予約できます。これは便利!…ですが2021年7月現在はまだaspect-ratioプロパティを使えるブラウザが限定されている(IEとSafariで使えない)のでcaniuse.comなどで対応ブラウザを確認しましょう

ちなみに手前味噌ですがリニューアル後のiretコーポレートサイトはほとんどの画像にwidth/height属性を記載するレギュレーションとしました。その結果ほぼすべてのページでCLS: 0を実現し、快適なUXを実現できているかと思います。

CLSの改善についてもっと詳しい記事は以下をご覧ください。

またaspect-ratioプロパティについてもっと詳しい記事は以下をご覧ください。

コアウェブバイタルには直接影響しないがパフォーマンスを改善するもの

コアウェブバイタルの指標には直接大きな影響を与えないものの、高速表示に効果的な画像の実装方法というものもあります。

オフスクリーン画像を遅延読み込み(lazy load)する

2020年よりHTML(W3CのHTML5ではなくHTML Living Standard。このHTML分裂も少し前話題になっていましたね)にネイティブLazy loadingがサポートされ、画像の遅延読み込みが格段に簡単になりました!
通常ブラウザは全ての画像をロードしてからページを表示させますが、画像にLazy loadingが指定されたページでは、ページスクロールに応じて都度画像がロードされるため、初回の表示を圧迫しません。

<img src="sample.jpg" 
     width="640" 
     height="360" 
     loading="lazy"
     alt="画像">

loading=”lazy”指定で画像の遅延読み込みができます。HTML Living Standard標準化仕様ですが、IEとSafariは2021年5月現在のところ非対応です。また仕様上CLSのところで紹介したwidth / height属性を書いてあげないと動作しない点に注意です。

このネイティブLazy loadingはしかし、LCPなどコアウェブバイタルの指標にはあまり影響しません。なぜなら遅延読み込みするべき画像はファーストビュー画像ではなくページ下部のオフスクリーン画像であることが多いため、ここを改善してもLCPには大きな影響がないことが多いのです。

また、ネイティブLazy loadingはビューポートの内にいるか否かに応じて作動する(Intersection Observer APIとほぼ同じ挙動と理解しています(間違ってたらごめんなさい!))ため、たとえばファーストビューに複数の画像を置きそれをz-indexで紙芝居のように動かすカルーセル…のようなケース(iretコーポレートサイトはこの形になっています)では使えません。

そのような場合にはLazyloadLazysizesLozard.jsなどのJavaScriptライブラリの出番ですね。
iretコーポレートサイトのトップページのヒーローイメージは単一画像ではなくスライドショーなので、2枚目以降の画像をLazysizesで遅延読み込みしています。
ネイティブlazy loadingとJSを使ったlazy loadingの両方を場面によってうまく使い分けていきたいですね!

ネイティブlazy loadingについてさらに詳しい記事はこちらをご覧ください。
Browser-level image lazy-loading for the web – web.dev

画像の非同期復号

<img src="sample.jpg"
     decoding="async"
     alt="画像">

decoding="async" 属性の指定で、画像の復号化が非同期で行われます。
つまりブラウザは画像の読み込みに際して重い画像の復号(デコード)とレンダリングを非同期化(並列化)し後回しにすることで、その他のテキストコンテンツのレンダリングを進めます。これにより、体感的なパフォーマンスが向上するとのこと。
HTML Living Standard標準化仕様で、IE以外の主要ブラウザで使用可能です。

さてこの画像の非同期復号はメインスレッドのCPU使用率に関わるためFIDに影響を与えるように思えますが、実際にFIDの観点でどの程度影響を与えるかは資料を見つけることができず、わかりませんでした🙇
というのも、これを紹介しているAddy Osmani氏の記事それに対するChris Coyier氏のコメントで若干の温度差が見受けられ(私の英語力の限界もあり)、自信を持ってこうだと言えるものはないと感じました。実際に計測したデータがあればいい話なので、これについては続報を待ちたいと思います。

decoding="async"loading="lazy" は併用できるか

併用できます。これについては下記の記事が参考になるかと思います。

というわけで「コアウェブバイタルを意識したフロントエンド改善レポート」第2回目は、ハイパフォーマンスな画像の考え方と実装手法について書いてみました。

P.S. アイレットではエンジニア、デザイナーを募集しています。詳しくは採用情報の募集職種ページをご覧ください。

次回の INSIDE UI/UXをお楽しみに👋

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。