画像遅延ロード Lazy Load をレスポンシブイメージ srcset に対応!

WordPress 4.4 でLazy Load をお使いの皆様、きちんと機能していますか?

WP4.4 を使用している場合は、機能しているか確認することをお勧めします。知らないうちに機能しなくなっているかも知れません

私も、レスポンシブイメージ srcset が有効になっていると、画像の遅延ロードが機能していないことに最近気づきました (^_^;)

使用中の lazy load の最新版を調べ、srcset 対応されていれば更新しておきましょう。srcset 対応がなかった場合は、下記記事を参考に自力対応っていうのもありです (^^)

lazyload-srcset

私が使っている画像の遅延ロードは Unveil Lazy Load をカスタマイズしたものですが、オリジナルの Unveil.js GitHubサイトを確認してみると、暫く更新されていないので自力で対応することにしました (^^)

画像遅延ロード Lazy Load (Unveil.js) で体感表示スピードアップ!
WordPress で画像が多いページの表示スピードを早くするための画像遅延ロード Lazy Load (Unveil.js)の設置方法を紹介します
画像遅延ロード Lazy Load (Unveil.js) で体感表示スピードアップ!

何故機能しなくなったのか

その前に srcset って何? という方は下記記事を参照して下さい

WordPress4.4 レスポンシブイメージ srcset の実験
WordPress 4.4 でサポートされたレスポンシブイメージの srcset と sizes について実験してみました。使用しているテーマでどのように機能しているか確認することが大切です。
期待どおりに動作していない場合には一時的に機能を停止することをお勧めします (^^)
Wordpress4.4 レスポンシブイメージ srcset の実験

それでは、srcset 対応していない lazy load を使っている場合の img タグがどのようになるのかを見てみます(見やすくなるように整形してます)

<img class="alignnone wp-image-2103 size-medium_large" 

src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" 

data-src="http://localhost/wordpress/wp-content/uploads/2013/08/c05-768x512.jpg"  alt="c05" width="768" height="512" 

srcset="http://localhost/wordpress/wp-content/uploads/2013/08/c05-150x100.jpg 150w, http://localhost/wordpress/wp-content/uploads/2013/08/c05-300x200.jpg 300w, http://localhost/wordpress/wp-content/uploads/2013/08/c05-768x512.jpg 768w, http://localhost/wordpress/wp-content/uploads/2013/08/c05.jpg 1024w, http://localhost/wordpress/wp-content/uploads/2013/08/c05-640x426.jpg 640w" 

sizes="(max-width: 768px) 100vw, 768px" 
/>

Lazy load とは、img タグで表示する src 画像を 1×1 等の代替画像にして、本来表示したい画像を data-src 等の別属性の名前にしておき、img タグがブラウザの表示エリアに入った時に javascript で data-src の値を src に書き戻して実際の画像を表示させています

たしかに、想定しているように img タグが出力されているようですが、その後に srcset と sizes の記述が追加されているのが分かります

レスポンシブイメージに対応しているブラウザは、src にセットされている画像ではなく、srcset に登録されている画像リストからブラウザがビューポートサイズに応じて画像を選択して表示してしまいます

従って、src は、レスポンシブイメージに未対応用のブラウザの為の画像指定となり、srcset 画像が実際に表示する対象に切り替わってしまう為に Lazy load が機能しなくなると言うわけです

srcset に対応するには

それでは、srcset に対応していきます

レスポンシブイメージがサポートされている場合は、画像の表示対象が src から srcset へ変わるので lazy load 機能の対象を src だけでなく srcset へも拡大すればOKです

img タグを出力する前に srcset, sizes が定義されていれば、それを data-srcset, data-sizes に置き換えて一時的に機能停止させてブラウザへ出力します

lazyloadスクリプトを使って、それを srcset, sizes に書き戻せば遅延ロードとなります

コードサンプル

WordPress の Celtispack プラグイン Unveil Lazy Load モジュールのコードを例に紹介します

PHPプログラム側の対応は、従来の処理に srcset と sizes を data-srcset と data-sizes に書き換える機能を追加するだけでOKです

static function unveil_attribute($matches)
{
        //$matches[0]  img タグ全体
        //$matches[1]  src 前の記述
        //$matches[2]  src 本体 (置き換え用の画像には base64 1x1 px transparent gif image を指定)
        //$matches[3]  src 後の記述
        // data-src あれば unveil 記述済み、data-orig あれば Lazy Load 記述済み、wp.com あれば jetpack photon 用に書き換え済みなので除外
        // flex-slider の場合も除外する
        $content = $matches[0];
        if (preg_match("#\.png|\.gif|\.jpe|\.jpeg|\.jpg#i", $matches[2])){
            if (!preg_match("#data-src|data-orig|wp.com|slide-image|flickr|instagr#", $matches[0])){
                $content = '<img' . $matches[1] . 'src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" ';
                //srcset, sizes が定義されていれば data-srcset, data-sizes に置き換えて一時的に機能停止するが、lazyloadスクリプト側で元に戻し有効化する 
                $matches[3] = str_replace(" srcset=", " data-srcset=", $matches[3]);
                $matches[3] = str_replace(" sizes=", " data-sizes=", $matches[3]);
                $content .= 'data-src="' . $matches[2] . '" '. $matches[3]. '>';
            }
        }
        return $content;
}

Unveil.js スクリプト側では、srcset と sizes に data-srcset と data-sizes の値をセットして元の状態に戻し、不要となった data-srcset, data-sizes を削除しています

/*
 * 画像の遅延ロード Unvail.js
 * Use a placeholder image in the src attribute - something to be displayed while the original image loads - and include the actual image source in a "data-src" attribute.
 *
 * <img src="bg.png" data-src="img1.jpg" />
 * WP4.4 からの srcset(data-srcset), sizes(data-sizes) 対応の処理を追加
*/
jQuery(document).ready(function($){
    /**
     * jQuery Unveil
     * A very lightweight jQuery plugin to lazy load images
     * http://luis-almeida.github.com/unveil
     *
     * Licensed under the MIT license.
     * Copyright 2013 Luís Almeida
     * https://github.com/luis-almeida
     */
    // celtis_s テーマで使用している background-image 形式に対応 
    // <div data-src="img2.jpg"  style="background-image: url('bg.png')"> 

    ;(function($) {

      $.fn.unveil = function(threshold, callback) {

        var $w = $(window),
            th = threshold || 0,
            images = this,
            loaded;

        this.one("unveil", function() {
          var source = this.getAttribute("data-src");
          var srcset = this.getAttribute("data-srcset");
          var sizes  = this.getAttribute("data-sizes");
          
          if (source) {
            if ($(this).is("img")) {
                $(this).attr("src", source);
                if (srcset){
                    $(this).attr("srcset", srcset);
                    $(this).removeAttr("data-srcset");
                }
                if (sizes){
                    $(this).attr("sizes", sizes);
                    $(this).removeAttr("data-sizes");
                }
            } else {
                $cval = $(this).css("background-image");
                if($cval == "none")
                    $(this).css("background-image", source);
            }
            if (typeof callback === "function") callback.call(this);
          }
        });

        function unveil() {
          var inview = images.filter(function() {
            var $e = $(this);
            if ($e.is(":hidden")) return;

            var wt = $w.scrollTop(),
                wb = wt + $w.height(),
                et = $e.offset().top,
                eb = et + $e.height();

            return eb >= wt - th && et <= wb + th;
          });

          loaded = inview.trigger("unveil");
          images = images.not(loaded);
        }

        $w.scroll(unveil);
        $w.resize(unveil);

        unveil();

        return this;

      };

    })(window.jQuery || window.Zepto);
    
    $("*[data-src]").unveil(400);
});

※このコードは、background-image の一部画像にも対応するようにカスタマイズしているので、オリジナルの unveil.js とは若干異なっています

 

これで、WP4.4 以上で srcset を使用しても、lazy load の機能が働くようになります (^^)

ちなみに、この機能は Celtispack プラグインの Ver1.9 で公開しています

 


まとめ記事紹介

go-to-top