Movable Typeで記事中の画像に遅延ロード効果の「Lazy Load」を一括適用する方法

lazy_load_01

MovableTypeのカスタマイズ情報などで大変お世話になっている小粋空間さんで、こんな記事があがっていたので反応してエントリーしてみます。

画像を遅延ロードする定番jQueryプラグイン「Lazy Load」: 小粋空間
jQueryで既存サイトの画像を「なんちゃって遅延ロード」する方法: 小粋空間

画像を遅延ロードさせて、ページ全体の表示速度を向上させるテクニックとして "かつて" 定番とされていた「Lazy Load」という手法、およびjQueryプラグインがあるのですが、最近のブラウザでは Lazy Loadが発動する前に画像を読み込みにいってしまうので、実際あまり効果ないよね?というか無駄なリクエストが増えちゃうよね?というのが、ある意味 Lazy Load 流行の終わりだったかと思います。

Lazy Load の jQueryプラグインの作者のコメントがこちら。

Latest version of Lazy Load is not a drop in replacement to your webpage. New browsers load image even if you remove the src attribute with JavaScript. Now you must alter your html code. Put placeholder image into src attribute of your img tag. Real image url should be stored data-original attribute.

via: Lazy Load Plugin for jQuery

日本語ではこの辺が分かりやすかった。

新しいブラウザだと期待した通りの動きをしない、というか遅延読み込みが出来ないから使う意味がないっていう感じです。むしろHTTPリクエストを実質減らせないどころか増やすので今現在使うのはとても微妙な感じです。増やすって言っても表示後にリクエストするんで、ちょっと違いますけど。

via: スクロールするまで画像を読み込まない(はずの)Lazy Loadについて :: 5509

で、jQueryプラグインの方もこの問題に対応した最新版になっていて、その導入開設をされているのですが、できればテンプレートなどにある静的な画像ではなく、記事中に貼り付けている画像にも一斉に適用したいなと思ったので、ボクなりの実装方法を紹介します。

Lazy Loadの問題点と改善版の要点

さて、実装に入る前におさらいです。まず、冒頭で紹介したリンクはチェックしといてくださいね。

旧Lazy Loadの問題点

Lazy Loadの基本的なアイデアは、IMGタグのsrc属性を後からJavaScriptで空に書き換えて画像を読みこませず、ページスクロールに合わせて少しずつ画像を表示させるというものでした。しかし、最近のブラウザがレンダリングの時点でsrc属性に入っている画像URLを読み込んでしまうため、実質意味が無い状態になっていました。

改善版Lazy Loadでは

そこで、最新のjQueryプラグインでは、src属性にはダミーの画像URLを入れておき、本当の画像URLはdata-original属性に入れておいてくだいねということになりました。

<img src="img/dummy.gif" data-original="img/original.jpg" />

みたいな。

ただ、実際にブログにLazy Loadを適用しようとする場合に、テンプレートなどに書いてある固定の画像タグは良いとして、すでに記事中に埋め込んでしまった画像タグはどうするの?っていう問題がでてきます。このブログも記事数が1000を超えていますし、手で直していくのは現実的ではありません。その辺りを解決したいなと。

Movable Typeの場合:画像タグを一括置換してしまおう

MTでは、regex_replaceモディファイアを使って文字列置換が可能なので、画像タグを一括で改善版Lazy Load用に書き換えてしまうことにしました。

ボクは本文(<mt:entrybody>)に画像1、2枚と概要を、続き(<mt:entrymore>)に画像無制限と残りの文章を書くというルールを決めているので、Lazy Loadを適用するのは<mt:entrymore>だけにしています。

<MTSetVarBlock name="regex0">/<img src="(https?:\/\/.+?)(\.jpe?g|\.gif|\.png)"/g</MTSetVarBlock>
<MTSetVarBlock name="regex1"><img class="lazy" data-original="$1$2" src="/img/s.gif"</MTSetVarBlock>
<mt:entrymore regex_replace="$regex0","$regex1">

regex_replaceモディファイアは、検索パターン文字列と置換文字列を配列で指定しますが、正規表現式のエスケープ等が面倒くさいので、一度 MTSetVarBlock に変数として格納するテクニックを使っています。この辺は下記ページを参考にさせていただきました。
regex_replaceを安全簡潔に書く小技 - エンジニアブログ - スカイアーク

で、正規表現の中身ですが大雑把にいうと下記のようなルールで置換するようにしています。

<img src="{JPG/GIF/PNGの画像URL}"

<img class="lazy" data-original="{JPG/GIF/PNGの画像URL}" src="{ダミーの画像URL}"

に書き換えています。

これはもちろん、元の画像タグが <img src="{JPG/GIF/PNGの画像URL}" という形式に沿っているという前提で成り立つ一括置換なのですが、僕の場合は画像タグをFlickrからコピペしたり、Amazon Quick Affiliate (JP)で出力されたタグをコピペしたりすることがほとんどなので、問題ありませんでした。

これ以外は、普通のLazy Load導入方法と一緒なので、bodyの最後などに、

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="/js/jquery.lazyload.min.js"></script>
<script type="text/javascript">
$(function() {
    $("img.lazy").lazyload({
        effect: 'fadeIn'
    });
});
</script>

とか、書いてあげればOKです。

見た目的なカスタマイズ

置換でsrcに入れる画像はロード中のマークなどを表示できればいいのでしょうが、記事中には色々なサイズの画像を貼り付けますし、Flickrなどからコピペしたタグにはwidth, heightの指定があるため、縦横比が滅茶苦茶になってしまう可能性が高く断念しました。単色の1px四方の画像とかでも問題はありませんが、どうも味気ないので、サイズ可変でグラデーションになった状態をCSSで表現してみました。

まず、srcに指定する画像は透明1px四方のGIFを用意しました。
そして、CSSに下記のように記述しました。

.lazy {
    background: #FFF;
    background: linear-gradient(top, #CCC, #666);
    background: -moz-linear-gradient(top, #CCC, #666);
    background: -webkit-gradient(linear, left top, left bottom, from(#CCC), to(#666));
}

一括置換でlazyクラスを付与されたIMG要素について、グラデーションの背景を指定しました。これで、画像サイズに関わらず綺麗なグラデーション画像からLazy Loadで元画像がフェードインするような効果が期待できます。
※透過GIFと背景グラデーションの組み合わせとかはもしかしてブラウザ依存あるかも??

lazy_load_02

こんな感じです。

JavaScriptをOffにされた場合の対処

IMGタグを下記変えて後からJavaScriptで書き換える・・・という方法なので、当然JavaScriptをOffにして見ている場合は画像はLazy Loadされません。

jQueryプラグインの開発元では一緒にnoscriptでシンプルな元画像を表示するように勧めていました。

その場合、こんな感じになるでしょうか?

<MTSetVarBlock name="regex0">/<img src="(https?:\/\/.+?)(\.jpe?g|\.gif|\.png)"/g</MTSetVarBlock>
<MTSetVarBlock name="regex1"><noscript><img src="$1$2" /></noscript><img class="lazy" data-original="$1$2" src="/img/s.gif"</MTSetVarBlock>
<mt:entrymore regex_replace="$regex0","$regex1">

ただ、この場合元画像とロード前のグラデーション画像が両方でる感じになるのであまりかっこよくはないですね。まあ、JavaScriptオフの人に完璧なレイアウトを見せなければならないかどうかは、それぞれ判断していただければ良いかと思います。

まとめ

すでに、たくさんの記事がある場合でもLazy Loadを導入できるので、なかなか便利な方法じゃないかと思います。ただ、説明中に書いたことも含め注意点があります。

  • 画像タグのルールが決まっていないと正規表現にはまらない
  • 画像タグのsrcがダミーになってしまうので、画像検索系のクローラーにはのらない(かも?)
  • JavaScriptをOffにしている人にはnoscriptなど一工夫必要
  • パフォーマンス向上を保証するものではない。

表示速度については、特に画像数が多い記事に関しては体感速度が上がったように思います。ただ、あくまで体感で説得力のあるベンチマークは取れていませんので、あしからず。

しかし、regex_replaceモディファイアは便利すなー。
正規表現かわいいよ正規表現。

同じカテゴリーの記事

このページの一番上に戻る
  • Facebook
  • Twitter
  • Tumblr
  • Instagram
  • miil