「Lazy Load」より「lazysizes」をおすすめする理由
遅延読み込みと言えば「Lazy Load」を思い浮かべる方が多いのではないでしょうか。
「Lazy Load」は遅延読み込みを実現するには素晴らしいプラグインですが、単体では動作せず、jQueryの追加が必要です。
また「Lazy Load」はAjaxなどを利用したDOM要素の変更を検出するために、何度もメインの関数を呼び出します。結果として表示が遅く、メモリを消費しがちです。
他にも視覚エフェクトなど、遅延読み込みとは直接関係のない機能で冗長化し、表示速度が振るいません。
そうした懸念を全て払拭してくれるのが今回ご紹介する「lazysizes」です。
レスポンシブイメージとの相性が悪いという誤解が多いようなので、イラストとデモページを交えて、わかりやすく解説します。
画像の遅延読み込みとは
画像の遅延読み込みとは、読んで字のごとく画像の読込を遅らせる技術です。
サイトを閲覧する際、ページの最後までスクロールするユーザーは限られています。ページの内容が意図したものと違ったり、途中でリンクをクリックしたりと、様々な理由でページを移動します。
とあるニュースサイトで計測したところ、ページの最後まで閲覧するユーザーの割合は3割り程度だったとこのこと。
そうなると表示されない部分の画像は無駄になります。これが縦に長いページや、画像の多いページの場合、無駄が多くなります。
その対策として、表示領域にない画像は転送せず、
ユーザーが画像を表示する直前に画像を転送しようという技術が生まれました。
これが画像の遅延読み込みです。
この技術を利用すれば、ユーザーはページの表示が早くなり、サーバ側はリソースを節約できるというWin-Winの技術です。
遅延読み込みの問題点
良いことばかりかというと、そうでもありません。
画像の表示が遅れることによるユーザー体験の低下
遅延読み込みの一番のデメリットは画像が遅れて表示されるという点です。
素早くスクロールすると画像の読み込みが追いつかないことがあります。
また、画像のサイズが大きかったり、転送が遅いサーバの場合も表示にラグが生じます。
その他にも遅延表示のためのスクリプトが重かったり、メモリを消費しすぎるようだと、動作が緩慢になります。
これではユーザー体験は低下してしまいます。
画像表示の遅れ対策
解決策として考えられるのは、
ユーザーの表示サイズに合わせた画像を複数用意する。
画像の転送に高速なCDNを利用したり、SSDサーバの導入など転送速度を高速化する。
画面に画像が表示される少し前に読込を開始する。
高速なスクリプトを利用する。
といった対策です。
画像遅延読み込みによるSEOへの影響
現在のSEOでは、Google botに正しく情報を伝えることが肝要です。
Google botでは遅延した画像を正しくクローリングできないことがあります。
せっかくSEOに有利なオリジナル画像を作成しても、正しくクローリングされなければ無いのと同じです。
javaScriptの解釈について、Googleの公式見解は「OnLoadイベントなどは実行する。」とのこと。
つまりクリックやスクロールといったユーザーのアクションのみをきっかけとしたものは実行しないということです。
「Lazy LoadはSEOに不向き? Lazy Loadで表示する画像をGooglebotは認識できないことがある」より
SEO対策
Google botは進化をしており、2015年には「一般的なモダンブラウザで閲覧するのと同じ状態で解釈することができる」という発表もありました。他にもAjaxも完璧に解釈できると豪語しています。
OnLoadイベントの話と矛盾している気もしないでもありませんが、Googleの中の人が言うのだから、そうなんです。たぶん…。
Google botに正しく画像が認識されているか確実に検証するには「Search Console」の「Fetch as Google」を利用しましょう。
気になるページをレンダリングして、正しく画像が読み込めていれば問題ありません。
HTML構文の問題
遅延して読み込ませる際は、src属性以外に画像のURLを指定ます。
そのため、画像を指定していないimgタグということになり、HTML構文的には正しくありません。
またjavaScriptが無効なユーザーは何も表示されないという問題もあります。
HTML構文対策
src属性にあらかじめサイズの軽いダミー画像を入れておくか、1pxの透明画像などのスペーサー用の画像をセットしておけば問題は解決できます。
以上の遅延読み込みありがちなデメリットの対策が可能なのが「lazysizes」です。
では実際に使い方を見ていきましょう。
「lazysizes」の使い方
まずは基本的な使い方。
「lazysizes」をGitHubの公式ページからダウンロード。
解凍して「lazysizes.min.js」をHTMLで読み込みます。
<script src="lazysizes.min.js" async=""></script>
普通に画像を表示する場合は以下のように記述すると思います。
<img src="image.jpg" />
lazysizesで遅延読み込みさせるには、2点変更します。
画像を「data-src」という属性で指定し、「lazyload」というクラスを追加します。
<img data-src="image.jpg" class = "lazyload" />
これだけで動作します。
ちなみに仮の画像を表示させるにはsrc属性を追加して設定します。
せっかくテストするなら美人を見ながらということで、「ぱくたそ」のモデル河村友歌さんの画像をお借りしてテストします。
Google Chromeで右クリックから検証を実行して更新してみてください。
既に画像が読み込まれているimgタグのクラスが「lazyload」から「lazyloaded」へ変更されてsrc属性で画像が追加されています。
また、表示されていない部分はsrc属性が追加されていません。
この状態でスクロールして、下の画像も読み込まれることを確認してみてください。
読み込まれていなかったimage03.jpgが読み込まれています。
lazysizesでレスポンシブイメージへ対応
srcsetのみを利用したサンプル
レスポンシブイメージとは、名前の通りレスポンシブデザインへ対応した画像の指定方法です。
スマホ用と、PC用の2種類の画像を用意しておき、デバイスの幅に合わせた画像を転送するという仕組みです。
適切なサイズで画像を転送できるため、画像の読み込みを早くしたい遅延読み込みとは親和性の高い技術です。
通常は以下のような指定をします。
<img sizes="(max-width: 1200px) 100vw, 50vw" src="image01.jpg" srcset="image01.jpg 600w, image02.jpg 900w, image03.jpg 1200w" />
src属性でデフォルトの画像を指定します。これが既定の画像となります。
srcset属性で幅に対応した画像を指定します。カンマ区切りで複数の画像とサイズを指定することができます。
この例ではデバイスの幅が600px以下の場合はimage01.jpgが表示されます。
幅が600px以上、900px以下の場合はimage02.jpg。
幅が1200px以上の幅の場合はimage03.jpgがそれぞれ表示されます。
sizes属性は名前の通り画像のサイズを指定します。
(max-width: 1200px)はメディアクエリの指定です。つまりブレイクポイントを指定することができます。この例では1200px以下の場合は100vwで表示という指定です。
vwはviewport widthの略で、ビューポートの幅に対する割合です。ビューポートは平たく言うとデバイス(ウィンドウ)の横サイズのことで、100vwが横一杯で、50vwなら半分。1vwなら1%といった具合に指定できます。(viewportがwidth=device-widthの場合)
こちらもカンマ区切りで複数指定できますが、最後の50vwは対応するメディアクエリがありません。この指定の場合は1200px以下の時は100vw、それ以上のサイズの場合(既定値)は50vwで表示という指定になります。
上記のレスポンシブイメージを「lazysizes」で適応させると以下のようになります。
<img data-sizes="(max-width: 1200px) 100vw, 50vw" data-src="image01.jpg" data-srcset="image01.jpg 600w, image02.jpg 900w, image03.jpg 1200w" class="lazyload" />
先程の例と同じようにclassに「lazyload」が付き、それぞれの属性に「data-」が付いただけです。
今回のデモページでは効果がわかりやすいようにウィンドウサイズと、画像のサイズを表示するようにしました。
srcset属性は内容の異なる画像を表示するためのものではない デモページですが、正しく動作させるために、まず幅600px以下のウインドウを作成していただき、URL(https://oxynotes.com/demo/lazysizes/test02/index.html)をコピペしてください。 この状態でだんだんとウィンドウサイズを大きくすると、指定したサイズに合わせて画像が切り替わります。このデモページには注意点があります。 レスポンシブイメージの指定は上記の方法以外にも、後述するpicture要素を使った方法があります。これは幅に応じて内容の異なる画像を表示することを想定しています。この方法だと横幅を拡大縮小するごとに画像が切り替わります。 対して、今回紹介したsrcset属性でサイズを指定する方法は「同じ画像のサイズ違いを表示する」という用途を想定しています。 デモページでは画像が切り替わったことをわかりやすくするために、内容の異なる画像を使用しましたが、本来の使用方法ではありません。 そのため、一度大きな幅に対応した画像が表示された後に、ウィンドウサイズを縮めても、大きな画像が表示され続けます(Google Chromeの場合)。 内容が同じならば、ウィンドウサイズを小さくした場合、縮小表示すれば済むからです。大は小を兼ねるというわけです。 (この辺の解釈はブラウザによって異なります) ちなみにはじめからウィンドウの幅が1200px以上の時に表示されるのは900pxと書かれた画像だと思います。 これは1200px以上の時(既定値)に50vwとしたため、1200pxの半分である600pxに最適な画像(900pxと書かれた画像)を選んだためです。 ウィンドウの幅が1800px以上で開けば半分の値が900pxを越えるため、1200pxと書かれた画像が読み込まれます。 既定値を80vwとすれば、1200*0.8=960となるため、1200px以上の幅で読み込んだ場合は必ず1200pxと書かれた画像が読み込まれます。 また40vwとすれば1200*0.4=480となるため600pxと書かれた画像が表示されます。 こうした挙動は「lazysizes」を利用していてもいなくても同じです。 レスポンシブイメージは便利な反面、ブラウザによっても動作が違うなど、まだクセがあります。正しく動作しているのか把握するには正しく理解することがかかせません。 「lazysizes」とレスポンシブイメージは相性が悪いと言われることがありますが、この辺の仕様を理解していないことが、勘違いの原因です。
pictureとsourceを利用したレスポンシブイメージのサンプル
続いてpictureとsourceを利用した例を解説します。これは「幅に合わせて異なる画像を表示する」という方法です。
こちらもまずは「lazysizes」を使わない例から。
<picture> <source media="(max-width: 600px)" srcset="image01.jpg"> <source media="(max-width: 900px)" srcset="image02.jpg"> <source media="(max-width: 1200px)" srcset="image03.jpg"> <img src="image01.jpg"> </picture>
picture要素で囲んだ中(コンテナ)にsource要素とimg要素を入れます。
sourceにはmedia属性でメディアクエリ(ブレイクポイント)を、srcsetでソース(画像)を指定しています。
img要素には今までと同じように画像を指定します。
こうするとウィンドウサイズ変えるごとに画像が切り替わります。
具体的は600px以下の時にimage01.jpg。
600~900pxのときにimage02.jpg。
1200px以上のときにimage03.jpg。
それ以上の場合(既定値)はimage01.jpgとなります。
「lazysizes」を利用した例
<picture> <source media="(max-width: 600px)" data-srcset="image01.jpg"> <source media="(max-width: 900px)" data-srcset="image02.jpg"> <source media="(max-width: 1200px)" data-srcset="image03.jpg"> <img src="image.jpg" data-src="image.jpg" alt="sample" class="lazyload" /> </picture>
これも上の例と同じで、data-srcsetとdata-srcを置き換え、img要素にlazyloadというクラスを追加しただけです。
srcsetのみのときとちがいウィンドウサイズ変えるごとに画像が切り替わることを確認してください。
オプションのJS APIを利用したサンプル
lazysizesは基本的にjavaScriptを追加しなくても動作しますが、JS APIを利用することで、様々な変更を加えることができます。
便利だなと思った機能にcustomMediaがあります。
これはブレイクポイントを設定するメディアクエリを登録しておき、一括で管理する方法です。
先程の例で適応すれば、以下のスクリプトを追加します。
<script> window.lazySizesConfig = window.lazySizesConfig || {}; window.lazySizesConfig.customMedia = { '--small': '(max-width: 600px)', '--medium': '(max-width: 900px)', '--large': '(max-width: 1200px)', }; </script>
まずlazySizesConfigのグローバルオブジェクトを生成している点に注意してください。この記述がないと動作しません。
生成したオブジェクトに値を入れることでオプションを設定しています。
続いてsourceのmedia属性にそれぞれ、--small、--medium、--largeと指定します。
<picture> <source media="--small" data-srcset="image01.jpg"> <source media="--medium" data-srcset="image02.jpg"> <source media="--large" data-srcset="image03.jpg"> <img src="image.jpg" data-src="image.jpg" alt="sample" class="lazyload" /> </picture>
このようにすることで、後でブレイクポイントを変更したいとなった場合、スクリプトの部分の数値を変更するだけで、一括で変換することができます。
他にも追加するクラス名を変更したり
window.lazySizesConfig.lazyClass = 'hoge';
他にも追加する属性名を変更したり
lazySizesConfig.srcAttr = 'data-hoge';
といったオプションを変更することができます。
もっとも、クラス名を変更したいという場合は少ないと思いますが…。
このほかにも沢山のオプションが用意されています。詳しくは公式ページのJS APIの項目をご覧ください。
サンプルにありますが、画像を読み込む前と後をフラグにイベントを実行したり、プラグインを利用してプリント実行時に画像を表示するといった使い方もできるようです。
これでlazysizesを利用した画像の遅延読み込みの解説は終わりです。
レスポンシブイメージについてもしっかりと理解して、積極的に取り入れていきたい技術ですね。