MENU CLOSE

lazysizesを使って
画像を遅延読み込みする

lazysizes
lazysizes

画像の遅延読み込み

通常Webページは読み込む時に画像をすべてダウンロードしてからページが表示されます。 まだ画面の領域に入っていない隠れている部分も含めて画像がどれだけあろうが全ての画像を読み込んでしまいます。 そうすると当然、ページのリクエストや転送量が増えてページ表示まで時間がかかりユーザーを待たせることになります。これを改善するのが「画像の遅延読み込み」です。 画面をスクロールして表示領域に入った画像だけを読み込ませることで、必要なタイミングで必要な分だけ画像が表示されるので無駄な読み込みが発生せずにページが軽くなります。

画像の多いサイトでページの高速化に取り組む時に最も効果が出やすい手法です。

lazysizesとは?

画像の遅延読み込みライブラリで、以下のような特徴があります。

  • レスポンシブイメージに対応している。(picture/srcset
  • jQueryに依存しない
  • classなどhtmlタグに直接属性などをを付けるだけで余計なオプションが少ない
  • 簡単にカスタマイズできる拡張プラグインも豊富
  • iframeにも対応
  • Google botにも認識されるのでSEO対策も問題なし

Githubに使い方とデモがあります。

lazysizesの使い方

1、ライブラリを読み込ませる

3パターンありますが、環境に合わせてどうぞ。

Githubからファイルをダウンロードしてlazysizes.min.jsを読み込ませる。

<script src="assets/js/lazysizes.min.js"></script>


CDNを読み込ませる場合は、こちらで各バージョンやプラグインを指定してコピペします。

<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js"></script>


Yarn もしくは npm でインストールして使う場合は以下。

// yarn
yarn add -D lazysizes

// npm
npm install -D lazysizes

インストールしたらJSでimportして読み込ませます。

import 'lazysizes';

2、imgタグの属性を変更する

遅延読み込みを適用したい画像の<img>タグのclassにlazyloadを、src属性にはダミー画像を、data-src属性に表示させる画像を設定します。

<img
class="lazyload"
src="data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7"
data-src="assets/images/lazyload.png"
alt="">

ここでダミーに使っているdata:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7というURLはbase64というデータ形式で1×1pxの透過gif画像を直接HTMLに文字列で埋め込んでいます。これなら外部ファイルとしてリクエストは発生しませんし、容量も最小限で済みます。ダミーは自分で用意したものでも構いませんが、サイズが大きくなると遅延読み込みが無意味になるのでご注意ください。

ダミーについてはこちらから持ってきました。

1x1の最小GIF・PNGファイル(透過/base64)

https://qiita.com/CloudRemix/items/92e68a048a0da93ed240

基本的な使い方は以上です!
これだけで遅延読み込みが実現できます。

DEMO
※サーバーが非力なので503エラーで画像が表示されない場合があります。すみません・・・

ちなみにiframeの場合は、ダミー画像が必要ないです。

<iframe class="lazyload" data-src="GoogleMapなど表示させたいURL"></iframe>

背景画像の遅延読み込みに対応させる

unveilhooksプラグインを使えば背景画像やscriptタグも遅延ロードできます。

//lazysizesを読み込む
<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js"></script>
//ライブラリの直後にプラグインを読み込ませる
<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/plugins/unveilhooks/ls.unveilhooks.min.js">

Githubからダウンロードした場合はplugins/unveilhooksディレクトリ内のls.unveilhooks.min.jsをコピーして使えばOKです。

<!-- 背景 -->
<div class="lazyload" data-bg="bg.jpg"></div>

<!-- JSなどのscriptタグ -->
<div class="lazyload" data-script="module-name.js"></div>

<!--CSSタグなどのlinkタグ -->
<div class="lazyload" data-link="my-style.css"></div>

<!-- videoタグ -->
<video class="lazyload" data-poster="poster.jpg" preload="none"></video>

<!-- CSSとJS -->
<div class="lazyload" data-script="my-script.js" data-link="my-style.css"></div>

サンプルソースは公式からお借りしました。

lazysizes unveilhooks extension

https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/unveilhooks

レスポンシブイメージに対応させる

スマホとPCなどデバイスに合わせて最適な画像を出し分ける手法ですね。
<picture>要素を使いメディアクエリで出し分けるのが最近の主流だと思いますが、そちらにも対応しているのがlazysizesの特徴でもあります。

<picture>
  <source
  media="(min-width:1440px)"
  data-srcset="assets/images/lazy-pc@2x.jpg">
  <source
  media="(min-width:768px)"
  data-srcset="assets/images/lazy-pc.jpg 1x, assets/images/lazy-pc@2x.jpg 2x">
  <img
  class="lazyload"
  src="data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7"
  data-src="assets/images/lazy-sp.jpg"
  alt="">
</picture>

imgタグは通常と同じように変更します。
あとはpicture要素で画像を出し分ける時に使うsourceタグのsrcset属性をdata-srcsetに変えてやるだけでOKです。

DEMO2
※サーバーが非力なので503エラーで画像が表示されない場合があります。すみません・・・

スクロールするとスマホとPCでアスペクト比の違う画像がちゃんと読み込まれますね。

ダミー画像の時に高さがずれる

ダミー画像と表示させる画像のアスペクト比が違う場合、画像を置き換えるまでの間、高さがずれてしまいます。

ダミー画像の置き換え時に高さがずれる

DEMOの場合、ダミーは1pxの透過ですからこうなってしまいます。
遅延読み込みなので仕方ないのですが、ちょっと早くスクロールしたら画面がガクガクしたりして気になりますよね。
他にも例えばページ内リンクを使ったスムーススクロールをJSで実装している場合、スムーススクロールの画面移動の速さに画像の置き換えが追いつかないので、変なタイミングで画像が読み込まれて高さがズレてしまい、止まって欲しい要素に止まらない、といったことが起こります。

かといって、同じサイズのダミー画像なんか用意してられないし、大きいダミー画像なんて用意してたら意味ないですよね。

これを解決する方法がlazysizesの拡張プラグインにあります。

lazysizes aspectratio extension

https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/aspectratio

このプラグインを使うと、指定したアスペクト比でダミー画像の高さを保ってくれます。

拡張プラグインはlazysizesをダウンロードした時にpluginsというディレクトリがありますので、その中にいろいろと入っています。
ここで使うのはls.aspectratio.min.jsなのでファイルをコピーしてきてlazysizesの後に読み込みます。

<script src="assets/js/lazysizes.min.js"></script>
<script src="assets/js/ls.aspectratio.min.js"></script>

CDNももちろんあります。

<script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/plugins/aspectratio/ls.aspectratio.min.js"></script>

使い方は簡単です。

<picture>
  <source
  media="(min-width:1440px)"
  data-aspectratio="1200/630"
  data-srcset="assets/images/lazy-pc@2x.jpg">
  <source
  media="(min-width:768px)"
  data-aspectratio="1200/630"
  data-srcset="assets/images/lazy-pc.jpg 1x, assets/images/lazy-pc@2x.jpg 2x">
  <img
  class="lazyload"
  src="data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7"
  data-src="assets/images/lazy-sp.jpg"
  data-aspectratio="750/900"
  alt=""
  style="width: 100%;">
</picture>

data-aspectratio属性に横幅/高さの形で追記します。単位はpxで数値のみでOKです。レスポンシブイメージでアスペクト比が変わる場合は各メディアクエリごとにdata-aspectratio属性を追記してあげればOKです。

そしてimgタグの横幅をCSSでwidth: 100%;に設定します。ここではサンプルなのでstyle属性に直書きしていますが、普通にCSSファイルに書いた方が良いです。

これでダミー画像が小さくでも画像のアスペクト比を保ったままズレずにページ表示できるようになりました。

DEMO3
※サーバーが非力なので503エラーで画像が表示されない場合があります。すみません・・・

アニメーションを付ける

表示する時にCSSでアニメーションを付けることもできます。

<picture>
  <source
  media="(min-width:1440px)"
  data-aspectratio="1200/630"
  data-srcset="assets/images/lazy-pc@2x.jpg">
  <source
  media="(min-width:768px)"
  data-aspectratio="1200/630"
  data-srcset="assets/images/lazy-pc.jpg 1x, assets/images/lazy-pc@2x.jpg 2x">
  <!-- class「animation」を追加 -->
  <img
  
  class="lazyload animation" 
  src="data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7"
  data-src="assets/images/lazy-sp.jpg"
  data-aspectratio="750/900"
  alt=""
  style="width: 100%;">
</picture>

imgタグにanimationというclassを追加します。animationは任意なので何でも構いません。全ての画像に同じアニメーションを設定する場合はなくても大丈夫です。

次にCSSを追記します。

.animation.lazyload,
.animation.lazyloading
{
  opacity: 0;
  visibility: hidden;
  transform: scale(.8);
}

.animation.lazyloaded{
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:1s ease;
}

遅延読み込み実行時にlazyloading、読み込み後にlazyloadedというclassが付くのでそれを利用してCSSトランジションを書きました。transitionでなくanimationでもできると思います。

DEMO4
※サーバーが非力なので503エラーで画像が表示されない場合があります。すみません・・・

Intersection Observer を使う

デフォルトのlazysizesはIntersection Observer APIに対応していません。
ただし、lazysizesをGithubからダウンロードすると、srcディレクトリにlazysizes-intersection.jsというファイルがあり、こちらはIntersection Observerを使っています。

読み込ませてみたところ、普通に使えるようでしたので、先ほどのDEMO4のJSを入れ替えてみました。

DEMO - Intersection Observer
※サーバーが非力なので503エラーで画像が表示されない場合があります。すみません・・・

Intersection Observerの方がパフォーマンスが良いので不具合がなければこちらを使えた方が良いのになーと思います。ただしpolyfillが必要です。

また、こちらの方法は動きますがおすすめはしません。
Github上にファイルは存在しますがドキュメントには掲載されていませんし、不具合やバグが起きても対応できない可能性がありそうです。 今回のようにDEMOで試すのには問題ないと思いますが、本番で使うことは避けた方が良いでしょう。

Intersection Observer APIについては過去記事がありますのでもし良ければこちらも合わせてご覧ください。

WordPressでも使いたい場合

WordPressでは、the_post_thumbnail()関数を使ってアイキャッチ画像を出力したり、記事内に埋め込んだ画像はthe_content()で出力される本文に自動的にimgタグとして入っています。これらをlazysizesに対応させる方法をメモしておきます。

the_post_thumbnail()の場合

function modify_post_thumbnail_html($html, $post_id, $post_thumbnail_id, $size, $attr) {
  if(is_admin() || is_singular('demo')){
    return $html;
  }
  $id      = get_post_thumbnail_id();
  $src     = wp_get_attachment_image_src($id, $size);
  $alt     = get_the_title($id);
  $html    = '<img class="lazyload" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN89wcAAt4B7N+P0IYAAAAASUVORK5CYII=" data-src="'.$src[0].'" alt="'.$alt.'">';
  return $html;
}
add_filter('post_thumbnail_html', 'modify_post_thumbnail_html', 99, 5);

post_thumbnail_htmlフックを使うとthe_post_thumbnail()で生成されるhtmlを変更できます。これでclass="lazyload"data-srcなど必要な記述を追記できますね。

the_content()の場合

記事に埋め込んだ画像やiframeに対応する場合です。

こちらはググると対応している方の記事があったので丸々そのまま参考にさせていただきました。

lazySizesでレスポンシブイメージの遅延読み込み(lazy load)をWordPressに組み込む

https://1010uzu.com/blog/lazysizes-responsive-images-lazy-load-wordpress

こちらの記事に書かれているadd_lazyload_tag()という関数を使わせていただくと、記事内のiframeタグとimgタグをlazyload対応できます!

さいごに

画像の遅延読み込みライブラリはたくさんありますが、正直どれでもいいですし、やろうと思えば自分でスクラッチで実装することも可能です。ただlazysizesはかなり簡単で高機能でなおかつ軽量ということで個人的にすごくおすすめです!まだ使ったことのない方は試してみてください。

また、Google Chromeではデフォルトで遅延読み込みができる機能が付いたみたいです。参考までに。

Chromeがネイティブlazy-loadをサポート、JSなしで画像を遅延読み込み可能に

https://www.suzukikenichi.com/blog/chrome-76-supports-native-native-loading/


ご指摘・ご質問はTwitterにお願いいたします。

記事一覧

RELATED

テキストの無限ループアニメーション【CSS + JS】
inoue
inoueのサムネイル
TIPS

【CSS + JS】テキストの無限ループアニメーション

shopify
inoue
inoueのサムネイル
TIPS

【Shopify】カートへの遷移を飛ばしてチェックアウトに進むボタンを設置する

PhotoSwipe v5
inoue
inoueのサムネイル
TIPS

【JS】PhotoSwipe v5を使って画像をポップアップ表示する

AVIF [ gulpでjpg・pngからAVIF画像を生成 ]
inoue
inoueのサムネイル
TIPS

gulpでjpg・pngからAVIF画像を生成する

MutationObserverでDOMを監視[PhotoSwipe(v5)+Swiper(v8)連携]
inoue
inoueのサムネイル
TIPS

【JS】MutationObserverでDOMを監視[PhotoSwipe(v5)+Swiper(v8)連携]

Google Sheets API スプレッドシートのデータをJSONで取得する
inoue
inoueのサムネイル
TIPS

【Google Sheets API】 スプレッドシートのデータをJSONで取得する

NEW POSTS

GA4連携人気記事ランキング機能を自作プラグイン化してみ【WordPress】
inoue
inoueのサムネイル
TRY

【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた

netlify UPDATE BUILD IMAGE [ビルドイメージの更新]
inoue
inoueのサムネイル
TRY

【netlify】ビルドイメージを更新 [ Ubuntu Xenial 16.04 → Ubuntu Focal 20.04 ]

Google Business Profile API [ PHPでクチコミ一覧取得 ]
inoue
inoueのサムネイル
TIPS

【PHP】Google Business Profile APIを使ってクチコミを取得する

screendot screenshot API
inoue
inoueのサムネイル
TRY

スクリーンショットのAPI「screendot」を使ってみた

window.matchMedia hoverを判定
inoue
inoueのサムネイル
TIPS

【window.matchMedia】メディアクエリでhoverが使えるデバイスを判定

lax.js
inoue
inoueのサムネイル
TIPS

lax.jsの使い方【スクロール連動アニメーションの実装】

ブログ記事一覧
  • HOME
  • TIPS
  • lazysizesを使って画像を遅延読み込みする