複数画像を効率よく使用する方法 ~ CSS ストライピング
魅力的なページを作ろうと思うと、いきおいたくさんの画像を使いたくなりますが、 その反面ページが重くなります。たくさん画像を使ってもなるべく重くならない方法、 あるいは大きな画像を使わずにページを構成する方法をご紹介します。
ここで紹介する方法は次の二つです:
CSS ストライピング
まずはこちらの例を見てください。数字の上にポインタを乗せると、色が変ります。
これはマウスのイベントで背景色が灰色である画像と橙色である画像を切り替えています。 1、2、...、5までのそれぞれについて、灰色と橙色の二つの画像を用意する必要がありますから、 計10個の画像を用意しないといけないことになります。
この時に10個の画像をバラバラにして用意するのではなく、ひとつの画像にまとめ、 CSS の backgroundPosition などの画像の場所指定によって見たいところだけ表示することもできます。 10個の画像をバラバラにダウンロードするよりも、10個の内容を含むひとつの画像をダウンロードするほうが、 プロトコルヘッダのコストの分、効率が良いといえます。
例えば、今回の場合バラバラにするとひとつひとつのファイルはおよそ 750 バイトです。 したがって、データサイズだけで 750 (バイト/ファイル) * 10 (ファイル) = 7500 (バイト) です。 それに加え HTTP のプロトコルオーバーヘッドがリクエスト、レスポンスそれぞれ、以下のように必要になります。
リクエストの例はこちら。サーバーに要求を出すたびにこのようなデータが送信されます。
GET /image1.png HTTP/1.1 Host: la.isakura.info User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Referer: http://www.keicode.com/page1.php Cookie: ST=113728968748a29d1c764023.37572412; PHPSESSID=c71c3305b73dd550d84353e0d0105679
レスポンスヘッダの例はこちら。データの頭に HTTP レベルだけでもこれだけのデータがくっつきます。
200 OK Date: Mon, 15 Sep 2008 04:12:15 GMT Server: Apache/2.2.9 (Unix) mod_ssl/2.2.9 OpenSSL/0.9.8g DAV/2 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 Last-Modified: Fri, 22 Aug 2008 08:33:06 GMT Etag: "121cab6-2bd-4550849607480" Accept-Ranges: bytes Content-Length: 701 Keep-Alive: timeout=15, max=97 Connection: Keep-Alive Content-Type: image/png ここにデータが続く
厳密に言えばこの他、HTTP レベル以外の TCP, IP 等のプロトコルヘッダもあります。 要は、画像をバラバラにすると画像データそのもの以外の、余計なやり取りが増えることになります。 したがって、画像をひとまとめにすると、プロトコルオーバーヘッドを減らせることになります。
ここでは、次のようなひとつの画像を用意しました。
画像をつなげてみたらデータ自体でも、ばらばらにしたときのファイルひとつのサイズ 750 バイトに対して、 それの単純な 10 倍の約 7500 バイトにはならず、3,733 バイトでした。画像のフォーマット的にも、 バラバラにするより一まとめの方が効率がというということになるのでしょうか。 (すみません、画像のフォーマットに関しては調べていません)
上の画像を span 要素の背景画像として設定し、画像位置を適切にずらして指定することによって、 必要な箇所だけ見えるようにしています。この際は CSS の background-position を指定します。
実装例
まず HTML は次のように書いています。
<div> <span class="number" num="1"> </span> <span class="number" num="2"> </span> <span class="number" num="3"> </span> <span class="number" num="4"> </span> <span class="number" num="5"> </span> <span class="number_end"> </span> </div>
CSS は次の通り.
div.number { float: left; width: 20px; height: 20px; background-image: url(rate_num_stripe.png); } div.number_end { float: none; }
上記に対して、次のような JavaScript で mouseover, mouseout を処理して表示画像を切り替えます。
Event.observe(window,'load',window_onload,false); function window_onload(evt){ set_hover_numbers(); } function set_hover_numbers(){ var elms = document.getElementsByClassName('number'); for(var i=0; i<elms.length; i++){ var num = elms[i].attributes['num'].value; if(num){ Event.observe(elms[i], 'mouseover', number_onmouseover, false); Event.observe(elms[i], 'mouseout', number_onmouseout, false); set_image(elms[i], false); } } } function number_onmouseover(evt){ var e = Event.element(evt); set_image(e, true); } function number_onmouseout(evt){ var e = Event.element(evt); set_image(e, false); } function set_image(div, mouseover){ if(!div){ return; } var num = parseInt(div.attributes['num'].value); var img_width = 20; var offset = (-1) * ( num - 1 ) * img_width; if(mouseover) { offset -= 5 * img_width; } div.style.backgroundPosition = offset + 'px' + ' 0px'; }
プリローディング
こちらは簡単です。バックグラウンドで画像ファイルをダウンロードさせることによって、 画像が必要になる前にブラウザのキャッシュに入れておく方法です。
new Image().src = '/images/image1.png';
実際の転送データ量等は変りませんが、裏側であらかじめ必要な処理をしておくことで、 体感的な速度を向上させることができます。