【WV.6】WordPressテーマ作成における画像読み込みとサイズ最適化 - チュートリアル - Capital P - WordPressメディア

【WV.6】WordPressテーマ作成における画像読み込みとサイズ最適化

Core Web Vital の連載6回目では、画像周りの処理を上げる。これはテーマに関わることであり、多くの場合テーマ本体の修正を必要とするだろう。今後テーマを新たに開発するケースがある場合は参考にして欲しい。LCPおよびCLSに関わる改善点だ。

Page Speed Insightsでの指摘

基本的には次の対処を行う必要がある。

  1. widthとheightの指定
  2. ファーストビューに入らない画像の遅延読み込み
  3. picureタグまたはsrcsetによる最適化された画像の出力

それでは、一つ一つ紹介していこう。

widthとheightの指定

画像にはwidthおよびheightを指定する必要がある。なぜかというと、その指定があれば、ブラウザは実際の画像を読み込む前にその画像のサイズがわかるからである。CSSで画像の表示サイズを変更するとしても、画像のサイズは必ず記載するようにしよう。Core Web VitalのCLSを減らすためにも必要だ。

Chrome Dev Toolでもわかるように画像の属性からアスペクト比を出している

ちなみに、WordPress標準の関数 wp_get_attachment_image などを使えばデフォルトでwidth & heightは入る。

ファーストビューに入らない画像の遅延読み込み

画像、iframeなどの埋め込み要素は画面に表示されない(=ファーストビューに入らない)場合、loading="lazy" 属性をつけることが推奨される。

<img src="path/to/img.jpg" loading="lazy" width="300" height="200" alt="" />

wp_get_attachment_image の場合はWordPress 5.5以降デフォルトで loading="lazy"なる。テーマなどで独自に画像タグを書いているパターンで問題になるケースが多いので、なるべく標準関数を利用しよう。また、投稿本文の画像も指定がない限りは loading="lazy" になる。デフォルトでフィルターがかけられているのだ。

ファーストビューの判断

さて、難しいのは「ファーストビューに入るか入らないか?」の判断だ。ファーストビューに入る画像を遅延読み込みにしてしまうと、LCPつまり「そのページの主要部分の描画完了」が遅れてしまうからである。ファーストビューに入る画像は優先的に読み込み、それ以外は遅延読み込みというのがLCPを健全に保つためのアプローチだ。

たとえば、この記事のように「ページの上部にアイキャッチ画像がある」という場合は簡単で、アイキャッチ表示のコードに loading="eager" を指定すれば済む。

the_post_thumbnail( 'post-thumbnail', [
    'loading' => 'eager',
] );

しかしながら、WordPressはCMSであり、とくにGutenberg以降のブロックエディターだと、ページ全体がブロックで構成されるようなパターンが増えてくる。この場合、なにがファーストビューかを決めることは原理的に難しい。カバーブロックかもしれないし、画像かもしれない。

投稿本文を書き換える

さて、一つのアイデアとして、「投稿本文に存在する1つめの画像がカバーブロックだったらeagerにする」というアイデアを紹介しよう。アプローチとしては次のようになる。

  1. まず、the_content フィルターを利用し、imgタグをパースする。
  2. クラス名をチェックし、wp-block-cover が含まれていたらeagerにする。
  3. 一つ以上のカバーブロックが見つかったら終了。
add_filter( 'the_content', function( $content ) {
    // カウンターを設定。
    $counter = 0;
    // 画像を正規表現で発見しつつ置換。
    $content = preg_replace_callback( '#<img([^>]+)>#', function( $matches ) use ( &$counter ) {
        list( $img, $attr ) = $matches; 
        if ( false !== strpos( $attr, 'wp-block-cover' ) ) {
            // カバーブロックでないので何もしない。
            return $img;
        }
        if ( 0 < $counter ) {
            // すでに置換済みなので何もしない。
            return $img;
        }
        // eagerに置き換え
        $attr = str_replace( 'loading="lazy"', 'loading="eager"', $attr );
        $counter++;
        // 新しいimgタグを返す
        return sprintf( '<img%s>', $attr );
    } );
    return $content;
}, 20 );

このコード自体は利用したことがないので、細かなバグなどあるかもしれないが、参考程度になるだろう。

背景画像はimgタグより遅い

カバーブロックでは、画像の固定表示などのオプションが存在する。これをオンにすると、画像が背景画像になる。他にもブラーフィルターなど、デザインの都合上、背景画像として画像を表示する必要があるケースは多い。

オプションを変えるとマークアップも変わる

背景画像はimgタグより読み込みの開始が若干遅い。これはCSSのスタイルコンテキストツリー構築完了を待ってから読み込むか否かを決めるからだ。また、背景画像には loading="lazy" のような仕組みも用意されていない。LCPの速度向上を目指す場合、このディスアドバンテージは覚えておいた方がよいだろう。

画像の適切なサイズでの表示

画像の適切なサイズを出力するためには、srcset 属性または <picture> タグを利用することが推奨される。いわゆるレスポンシブ画像というやつだ。以下、2つのやり方をそれぞれ見てみよう。

srcsetとsizes属性

WordPressの画像出力はsrcsetをサポートしており、次のようにすべての画像サイズがsrcsetとして出力される。

<img data-attachment-id="5171" loading="lazy" width="1536" height="2048" src="https://example.com/wp-content/uploads/2021/04/IMG_1055D-1.jpg" alt="" class="wp-image-5171" srcset="https://example.com/wp-content/uploads/2021/04/IMG_1055D-1.jpg 1536w, https://example.com/wp-content/uploads/2021/04/IMG_1055D-1-300x400.jpg 300w, https://example.com/wp-content/uploads/2021/04/IMG_1055D-1-338x450.jpg 338w, https://example.com/wp-content/uploads/2021/04/IMG_1055D-1-768x1024.jpg 768w, https://example.com/wp-content/uploads/2021/04/IMG_1055D-1-1152x1536.jpg 1152w" sizes="(max-width: 1536px) 100vw, 1536px">

投稿本文内ならこれでもよいが、正しいsizesを設定することでウィジェットエリアなどでの表示で最適化をはかれる。sizes属性はメディアクエリと一緒に表示幅を指定する属性で、ブラウザはこれを参考にsrcsetの中からもっとも適切なものを選ぶ仕組みになっている。詳細はMDNの記事レスポンシブ画像も参照してほしい。

今回はサイドバーにある新着投稿リストのようなものを想定し次のようなレイアウトで適切な画像サイズになるようにしよう。

  • PCなら2カラムのサイドバーでリスト表示、サムネイルサイズ thumbnail150px × 150px
  • スマホなら1カラムでカード型レイアウト、サムネイルサイズ card 300px × 300px
the_post_thumbnail( 'thumbnail', [
    'sizes' => '(max-width: 350px) 300w, 150w',
] ); 

上記のように書いておけば、ブラウザが適切に判断してくれるはずだ。マークアップも変わらないし、後方互換(非対応ブラウザにはただのimgタグ)もたもたれる。

pictureタグの利用

新規に作成するテーマの場合は picture タグの利用も検討してみよう。ただし、WordPress標準で picture タグを出力する機能はない(はず)なので、独自実装の関数などを作成する必要がある。pictureタグの最終的な出力は次のようになる。

<picture>
    <source media="(max-width: 350px)" srcset="[email protected] 2x, vertical.jpg" /> 
    <source media="(max-width: 768px)" srcset="[email protected] 2x, slate.jpg" /> 
    <source media="(min-width: 769px)" srcset="[email protected] 2x, landscape.jpg" /> 
    <img src="path/to/image.jpg" alt="" width="400" height="300" />
</picture>

srcsetとpictureタグの違いは、筆者の知る限り以下の通り。詳しい方はぜひご意見いただきたい。

  1. srcsetはあくまでブラウザに対する提案(選択的)だが、pictureはメディアクエリに応じたsourceが採用される(強制的)
  2. srcsetはピクセルデバイス比率とサイズを同時に指定することはできないが、pictureならできる。
  3. pictureは「アートディレクション用途」と考えられている。ラップトップでは横長の画像、タブレットやモバイルでは縦長の画像という形で最適な画像を表示したいときに使う。

よりリッチなのはpictureタグなので、単に解像度を変更するだけに止まらない、最適化したレイアウトを提供したいなら、pictureタグでの実装を検討しよう。

画像のサイズ

どちらの方法で実装するにしても、重要なポイントはWordPressの画像サイズを適切なものにすることだ。WordPressではデフォルトのサイズとして以下のものがある。

  • サムネイル thumbnail
  • ミディアム medium
  • ラージ large
  • アイキャッチ画像 post-thumbnail

テーマ側からこれらに対して add_image_size で画像のサイズを追加していくことになるのだが、デザインの段階から「このサイトでは何種類の画像を使い、何パターンあるのか」ということをよく検討しておこう。デザイナーと開発者が異なる場合は尚更だ。すり合わせをきちんとし、どのような意図で画像が選ばれているのかを確かめておく必要がある。あっちでは正方形、こっちでは4:3、ここは16:9……などとバラバラのアスペクト比のデザインになっていると適切なサイズの画像配信は望めない

柔軟な画像配信:Tachiyonの例

実際に採用できるかはともかく、WordPress界のトップエンジニアが集う会社でどのようなソリューションを提供しているのかも紹介しておこう。

Human Madeの提要するTachyonというソリューションは「画像のサイズどれやねん」問題を完全に解決しており、画像のURLの末尾にクエリパラメーターを付与することで、オンザフライで画像を生成してくれる。このソリューションだと add_image_size だなんだという悩みはすべてなくなる。アフィリエイトブロガーはAmazon.comの商品画像が同等の機能を持っていることを知っているかもしれない。

Tachyonのアーキテクチャ

Tachyonがそんな簡単に導入できるかというとそんなことはない。Tachyonをセットアップして利用できたら、それだけでつよつよエンジニアの仲間入りだ。しかし、将来的には画像のクラウドホスティングもより一般的になって、こうした機能が簡単に使えるようになるかもしれない。

柔軟な画像配信:Cloudflare(追記)

CloudFlareにも画像リサイズサービス Cloudflare Image Resizing があるようだ。URLベースでもできるし、WorkerというAWS Labmda on Edgeのようなサービスも使える。筆者はProプランしか使ったことがないので試せないが、ビジネスプラン以上を利用している方は試してみてほしい。問題はローカルで再現できないので動いているかどうかわからないという点だろうか。

まとめ

画像はコンテンツとして重要な地位を築いているため、その適切な読み込みはサイトにとっても重要な要素となるだろう。以下のポイントを抑え、最適な画像配信を目指してほしい。

  • 画像のwidth & height を必ず入力する
  • ファーストビューに入らない画像は loading="lazy" にする。
  • 上記をサポートすべく、なるべく標準のWordPress関数を使う
  • picture, img(srcset, sizes) を駆使して閲覧環境ごとに最適化されたレスポンシブ画像を提供する。
  • 画像のサイズをテーマ作成の段階からきちんと決めておく。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください