Webページを表示する時、画面に表示されていない無駄な画像までロードしていませんか?
画像のロードは、Webブラウザの表示を遅らせるだけでなく、サーバ側にも負荷を与える厄介な処理でもあります。"Lazy Load"は、そんな画像ファイルのロードタイミングを、JavaScript側で制御できるjQueryプラグインです。
JavaScriptで画像ファイルのロードのタイミングを制御できるということは、画像ロードによるサーバ負荷を分散させるアプローチが可能になります。また画面に一度も表示されないような画像はロードさせないように制御すれば、負荷そのものを減らすことも可能になります。
Webブラウザ側でも、ページ自体をロードする際に一括で画像ファイルをロードさせる必要がなくなるので、表示速度の改善に繋げることができます。動作環境は、モダンブラウザはもちろんのこと、IE8以上から動くことが確認されており、かなり実用的なjQueryプラグインになっています。
▼公式サイト
http://www.appelsiini.net/projects/lazyload
▼ソースコード
https://raw.github.com/tuupola/jquery_lazyload/master/jquery.lazyload.js
▼ミニファイ版ソースコード
https://raw.github.com/tuupola/jquery_lazyload/master/jquery.lazyload.min.js |
1. まずは使ってみましょう
Lazy Loadは、img要素側とjQuery側の2箇所に仕掛けを作りこみます。
まずはimg要素。"data-original"というプロパティを追加します。このプロパティには、表示したい画像のファイルパスを指定して下さい。"src"プロパティについては、1x1ピクセルのファイルサイズの小さな画像をダミーとして指定します。
ここで透明の画像を指定すればロード中は背景色になり、灰色の画像を指定すればロード中は灰色の四角いボックスが表示されます。どんな画像ファイルでも指定して良いですが、負荷を下げる目的で利用するのであれば、1x1ピクセルのgif画像が一番妥当でしょう。
<img data-original=“img/dummy.jpg” src=“img/dummy.gif” width=“640” height=“480”>
次に、このimg要素に対して、遅延ロードさせるための機能を追加します。Lazy LoadはjQueryのプラグインなので、jQuery本体のロード後、Lazy Loadのライブラリをロードします。その後、jQueryのセレクタを利用して、遅延動作させたいimg要素に対して、メソッド"lazyload"を実行します。
<script src="./js/jquery.min.js"></script. <script src="./js/jquery.lazyload.min.js"></script> <script> $("img").lazyload(); </script>
これで終わりです。
引数として何も指定していない場合は、img要素がウィンドウ内の表示範囲へ入った際に、画像ファイルのロードが開始されるという動作をします。引数へエフェクト用パラメータを指定すれば、ロード後の動作を自然な形へ変えることができます。
<script src="./js/jquery.min.js"></script> <script src="./js/jquery.lazyload.min.js"></script> <script> $("img").lazyload({ effect : 'fadeIn', effectspeed : 500 }); </script>
このサンプルを実行すると、画面内にimg要素が入り込んだ際に、500ms程度のフェードイン処理が施されます。これだけでも、ビジュアルは十分に良く見えるでしょう。負荷の面でも、画面内に入るまでロード処理が行われないため、クライアント・サーバ双方で低減が行えています。
2. どういう風に負荷低減されるか
Webブラウザ内で何が起こっているのかを確認してみましょう。簡単なサンプルを作成しました。一つ目は単純にimg要素を使って、12枚のpngファイルを表示するというものです。
▼サンプル1
<!DOCTYPE html> <html> <head> <title>Sample</title> </head> <body> <h1>Sample</h1> <img src="img/test01.png" width="640" height="480" /> <img src="img/test02.png" width="640" height="480" /> ・ ・ ・ <img src="img/test12.png" width="640" height="480" /> <script src="js/jquery.min.js"></script> </body> </html>
次のサンプルは、Lazy Loadを活用してイメージをロードした例です。Webブラウザ上には、一番上の一枚の画像のみが表示される状態にしてみました。
▼サンプル2
<!DOCTYPE html> <html lang="ja"> <head> <title>Sample</title> </head> <body> <h1>Sample</h1> <img data-original="img/test01.png" src=“img/dummy.gif” width="640" height="480" /> ・ ・ ・ <img data-original="img/test12.png" src=“img/dummy.gif” width="640" height="480" /> <script src="js/jquery.min.js"></script> <script src="js/jquery.lazyload.min.js"></script> <script src="js/busy1000ms.js"></script> <script> $("img").lazyload({ effect: 'fadeIn', effectspeed: 200 }); </script> </body> </html>
Chrome Frameを利用して、それぞれのWebブラウザの動作を確認してみましょう。まずはサンプル1,img要素で普通に画像をロードした場合です。
ローカル環境でテストしたということもあり、画像のロードがやたら高速になってしまいました。しかしそれでも、有益な情報は多く得られたと思います。
上から5番目の「Send Request (x13)」では、計12枚の画像とjQueryファイルをロードしています。それも一斉にです。近年は、Apacheなどのサーバサイド側の設定で、ステートフルコネクションを無効にすることで、同時処理数を向上させ最適化するのが主流です。このような同時接続はもはやあたりまえでしょう。とはいえ、Webページアクセスの初動でこんなにも多くの接続が行われるというのは、ゾッとするものがあります。
アクセス開始からペイントまで、130ms程度の時間を要しています。ただし、ペイントの後も継続して画像のロードが行われいるため、一概にこれが最短表示時間とは言えないでしょう。
次に、Lazy Loadを使った場合です。
80msっとそれなりに高速化されましたが、一番注目すべきは、ファイルのロード数です。計3つのファイルをロードした後、HTMLのパースを一度完了させ、その後1枚のpngファイルをロードしています。つまり計4枚だけです。
最初の3つの中には、gifファイルも含まれていますが、1x1ピクセルと非常に小さいため、負荷のうちに入っていません。そして、画面に写っていない残りのpng画像も、ロードされていません。
画像が画面に映り込んでから表示されるという動きをするので、アクセス直後に一気に負荷が集中するというWebシステムの課題も緩和されます。毎回大量のファイルをやりとりするのでなく、ジワジワと拾いに行くといった動作ができるようになるのです。また、画面に一度も表示されることの無かった画像は、ロードされないままとなり、通信量削減にも繋がっています。業務システムの場合は、画像ファイルでもそこそこ負荷になったりするケースもありますので、有効な策と言えるのではないでしょうか。
念の為に、本当にIE8でも想定通りの動きになるか確認してみましょう。IE8はタイムライン機能が無いので、開発者ツールを使って、ページの一番上を表示した際の要素の状態をそのまま吐かせます。
一番上のimg要素だけが、ロード済みの状態になっています。
この画像だと見難いので、ある程度横まで伸ばしたものも見てみましょう。
"src"プロパティが正しいpngファイルでセットされています。意図した通りに動作していますね。
3. ワンステップ上へ
ロード方法はこれだけではありません。公式ページは情報量がかなり少ないですが、他のjQuery機能を活用できるため多彩なバリエーションを持っています。性能最適化の観点で見ればこういうものも使えるでしょう。
$(function() { $("img:below-the-fold").lazyload({ event : "sporty" }); }); $(window).bind("load", function() { var timeout = setTimeout(function() {$("img").trigger("sporty")}, 5000); });
このサンプルは、5秒後にロードを開始するという動作です。先ほどは画面に見えてからロードするという動作でしたが、こちらはユーザがどこを見ているのかに関係なく、一定時間後にロードさせるという動作になります。一見微妙にも見えるこの動作、Webブラウザの仕組み、パフォーマンスの最適化の観点で見ると、結構使い道が広いように思えます。
パラメータへ100msを与えるだけでも、効果は高いように思えます。setTimeoutで指定された時間はブラウザ側に制御が戻るため、Webブラウザは余裕を持ってペイント処理を行えます。画像のロード処理をスキップした状態で、画面を表示できるのです。HTMLに埋め込まれたデータの内容が、画像のロードに邪魔されること無く素早く表示されるので、スループットの向上が期待できるでしょう。何が何でも先にデータをロードして、画像の読み込みは後回しにしたいという場合に活用できるでしょう。画像のロード自体は平行して行われるため、ロード中だからと言ってHTMLのレンダリングが抑制されることはありません。。が、影響は皆無とは言えません。場合によっては、UXを殺してしまうことになりますが。
Webシステムは今まで、単純にデザインを表示するためのスクリーンでしかありませんでした。しかしHTML5の普及やJavaScriptの高速化により、Webブラウザをアプリケーションを動かすためのアプリケーションプラットフォームとして扱えるようになり、クライアントで実装する機能も増えつつあります。そんな中、パフォーマンスに悩みを抱えることも多くなりました。
今回の画像ファイルに限らず、JavaScriptやCSSにも遅延ロードをさせるライブラリが豊富に出て来ました。余分な処理をスキップするという動作が、簡単かつ柔軟に行えるというのは、Webの新しい性能アプローチの可能性を想像させます。業務システムのように大量データを画面に吐き出させなきゃいけないようなケースで、"データ表示が最優先!"、"デザインは後回し!"、といったアプローチも、今後広まることがあるかもしれません。