レ点腫瘍学ノート

Top / 日記 / 2021年 / 3月8日

Lazysizes.jsを使うとCLSが発生する問題(解決済)

16f4ac0c0a.jpg

lazyload(画像の遅延読み込み)するためにlazysizes.jsを使うとスペースホルダーによりCLS (Cumulative Layout Shift)が発生する問題に関して記載するページです。このサイトも遅延読み込みのためにlazysizes.jsを使ってスペースホルダーを使うとCLSが発生する問題について長らく悩まされてきました。lazyloadは現代WEBには欠かせない技術ですが、ようやくひとまず解決できたのではないかと思えるところまで到達したので、今回の対応策を記載しておきます。

追記(2021/6/21):その後に問題が生じて再びCLSが生じるようになってしまいました。詳しくはこちらの記事をご覧ください。

CLS(Cumulative Layout Shift)とは

CLSとはコアウェブバイタルの1つの要素で、SEOのために非常に重要な因子です。ページの読み込み中に表示されるページ内要素が、読み込み完了までにずれることを指し、ユーザー体験を悪化させるものとしてできるだけCLSが出ないようなレイアウトをすることが求められています。このCLSはpagespeed Insightsの評価要素にもなっており、CLSが残ったまま放置されているとSEOにとって悪影響なのです。

Cumulative Layout Shift (CLS)
This post introduces the Cumulative Layout Shift (CLS) metric and explains how to measure it.
https://web.dev/cls/

CLSを無くすためには様々な方法を組み合わせて対処する必要がありますが、とくに画像のレスポンシブ対応ではCLSに影響するものがたくさんあるので、画像のHTMLをどう出力するかには気を遣う必要があります。lazyload(画像遅延読み込み)やwebp fallbackと両立させるためにはなおさらです。

【重要】コアウェブバイタルとは? LCP/FID/CLSをわかりやすく解説【SEO情報まとめ】 | 海外&国内SEO情報ウォッチ
Googleが発表した、最新のUX重要指標「core web vitals(コアウェブバイタル)」の3つ「LCP」「FID」「CLS」について、その意味やそこから見える問題点・改善基準をわかりやすく解説する。また、パンくずリストの位置など最新SEO情報もまとめた。
https://webtan.impress.co.jp/e/2020/06/05/36210

lazysizes.jsでは当初CLSにどのような問題が生じていたか

lazysizes.jsはlazyload(画像遅延読み込み)のために非常に人気のあるスクリプトですが、CLSが発生するという問題がありました。CLSがあるとSEOにとって好ましくないので、SEOのためにlazysizes.jsを使っているサイトにとっては本末転倒です。

もともとこのサイトはPukiwikiを使っていますが、Pukiwikiでは画像を出力するのにref.inc.phpを使用します。ref.inc.phpでは画像の入力に対してHTMLを吐きますが、lazyloadおよびwebp fallbackに対応するために当サイトのref.inc.phpは下記のようなHTMLを出力していました。下記は横750 X 縦500の画像サイズの例です。

img{
	width:100%;
	height:auto;
}
<picture>
<source type="image/webp" data-srcset="sample.webp">
<img class="lazyload" src="spaceholder.gif" data-src="sample.jpg" width="750" height="500">
</picture>
JPGやPNGなどの画像をWEBP形式にすることによってファイル容量を減らすことができ、ひいては通信速度の向上によりPagespeed insightsのスコアの改善を期待することができます。しかしWEBP画像は現時点ではSafariに対応しておらず iPhoneやiPadやMacのSafariも2020年秋のアップデートからWEBP

しかしこれでは、ダミーgifファイルが1X1サイズなので、一瞬だけ750X750のサイズとして表示されてしまいlayout shiftが生じます。つまりこの画像ファイルが遅延読み込みされる間、画像よりも下にある文章などがいったん低い位置に表示され、画像の読み込みが完了した時点で250px分だけずれる(CLSが生じる)ことになるのです。

AdSenseと画像のCLS(Cumulative Layout Shift)の改善
Core Web Vitalsの1つである画像の読み込みを遅らせてブログ、サイトの表示速度を疑似高速化するlazysizes等の遅延表示機能によって発生する表示レイアウトのズレを数値化したCLS(Cumulative Layout Shift)の改善方法を紹介...
https://escaper3rx3air.blog.fc2.com/blog-entry-125.html

webp fallbackがない場合でもやはり同様です。webp fallbackを必要としない場合は下記のようなHTMLになると思いますが、やはりプレースホルダが1X1サイズなので一瞬だけ高さが750と表示されてしまい、250px分のLayout Shiftが発生してしまうのです。

<img class="lazyload" src="spaceholder.gif" data-src="sample.jpg" width="750" height="500">

もともとimgタグの中にwidth="XXX" height="XXX"を記載しているのはレスポンシブ対応にしたときにCLSが発生しないようにするためのもので、lazysizesを使っていない場合はこのwidthとheightでLayout Shiftが発生しなくなるのですが、lazysizes.jsを使っている場合はdata-srcの読み込みが終了するまでの間、widthとheightが無視されてしまい、どうしてもLayout Shiftが発生してしまいます。

CLSを無くしたいのですが、これについては対応をググってもなかなか良い方法が見つけられませんでした。

lazysizes.jsでCLSを無くすために当サイトがとった解決策

Lazy Load(画像の遅延読み込み)するプラグイン lazySizes.js
画像を遅延読み込みするプラグインは多数ありますが、lazySizes はレスポンシブイメージに対応、jQueryに依存しない、余計なオプションが少ないなどでおすすめです。 lazySizesの使い方 GitHub よりzipを
https://hibidesign.com/memo/web/181

長らく困っていたのですが、ようやく上記のサイトを見つけて、lazysizes.jsにls.aspectratio.min.jsというプラグインがあることに気がつきました。これはどうやらlazysizes.jsで読み込む画像にアスペクト比を反映させるプラグインのようです。このプラグインをlazysizes.jsのあとに読み込ませて、imgタグにはdata-aspectratio="750/500"を記載してやります。

<picture>
<source type="image/webp" data-srcset="sample.webp">
<img class="lazyload" src="spaceholder.gif" data-src="sample.jpg" data-aspectratio="750/500">
</picture>

こうすると、なんとLayout Shiftが発生しなくなりました。悩み始めてから約1年かかってしまいましたが、ようやく解決するに至ったのでした。

lazysizes.jsのプラグインも一括してjsdelivrで読み込む方法

jsdelivrでlazysizes.jsを読み込んでいる場合は、プラグインも一括で読み込むことができます。HTMLに下記のタグを記載しておくだけです。

<script src="https://cdn.jsdelivr.net/combine/npm/[email protected],npm/[email protected]/plugins/aspectratio/ls.aspectratio.min.js" async></script>

当サイトはdiv要素などでも遅延読み込みを可能にするためのunveilhooksプラグインも使用しているので、これも含めて一括で読み込む場合は下記の通りになります。

<script src="https://cdn.jsdelivr.net/combine/npm/[email protected],npm/[email protected]/plugins/unveilhooks/ls.unveilhooks.min.js,npm/[email protected]/plugins/aspectratio/ls.aspectratio.min.js" async></script>

なお、Pukiwikiのref.inc.phpは下記のようになります。

if ($is_image) { // 画像
  if ( PLUGIN_REF_WEBP_FALLBACK ) {
    if(strpos($url,$script) !== false){
      $url = str_replace($script, '', $url);
    }
    $urlwebp = pathinfo($url, PATHINFO_DIRNAME ) . '/' . pathinfo($url, PATHINFO_FILENAME ) . '.webp'; //同じディレクトリにwebp画像があるか探す
  }
  if ( PLUGIN_REF_WEBP_FALLBACK && file_exists($urlwebp) ) {
    $params['_body'] = "<picture><source type=\"image/webp\" data-srcset=\"$urlwebp\"><img class=\"lazyload refimg\" src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"$url\" alt=\"$title\" data-aspectratio=\"$width/$height\"></picture>"; //webp画像fallback
  } else {
    $params['_body'] = "<img class=\"lazyload refimg\" src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" data-src=\"$url\" alt=\"$title\" $info>";
  }
  if (! $params['nolink'] && $url2) {
    $params['_body'] = "<a href=\"$url2\" title=\"$title\">{$params['_body']}</a>";
  }
} else {
  $icon = $params['noicon'] ? '' : FILE_ICON;
  $params['_body'] = "<a href=\"$url\" title=\"$info\">$icon$title</a>";
}

その後に生じた問題 (2021/6/21追記)

以前はうまくいっていたlazysizes.jsでCLSが生じる問題の対策 以前に「Lazysizes.jsを使うとCLSが発生する問題」の記事を書いていました。画像の遅延読み込みを可能にするJavaScriptであるlazysizes.jsを使うと、CLSが生じてpagespeed insightの評価スコアが下がってしまうという問
JPGやPNGなどの画像をWEBP形式にすることによってファイル容量を減らすことができ、ひいては通信速度の向上によりPagespeed insightsのスコアの改善を期待することができます。しかしWEBP画像は現時点ではSafariに対応しておらず iPhoneやiPadやMacのSafariも2020年秋のアップデートからWEBP
HTMLコーダー&ウェブ担当者のためのWebページ高速化超入門 | 佐藤 あゆみ |本 | 通販 | Amazon
Amazonで佐藤 あゆみのHTMLコーダー&ウェブ担当者のためのWebページ高速化超入門。アマゾンならポイント還元本が多数。佐藤 あゆみ作品ほか、お急ぎ便対象商品は当日お届けも可能。またHTMLコーダー&ウェブ担当者のためのWebページ高速化超入門もアマゾン配送商品なら通常配送無料。
https://amzn.to/3rvWRcG

この記事に対するコメント

このページには、まだコメントはありません。

お名前:

更新日:2021-03-08 閲覧数:3050 views.