2013/01/15更新

[CSS] CSSで利用する画像をSpriteにするかBase64にするかを考察してみた

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
Webページを作る際に、CSSに使う画像をSprite化するのが良いのか、Base64エンコーディングしてCSSに埋め込むのが良いのか、 最近良く議論になります。
今回は、その議論をじっくりと考えてみた結果をブログに書きたいと思います。

画像



背景

仕事でWebベースのゲームやSNSを作成することが多くあります。
HTML,JavaScript,CSS,画像を使って、画面を構成する仕組みです。
そんな仕事で、最近良く以下のような話題が聞かれます。
アプリケーションで利用するアイコンやボタン背景画像などを、Base64エンコーディングしてCSSに埋め込むべき?
それとも、Sprite画像にして読み込むべき?

この話題は、既に話しまくられている話題かもしれませんが、自分なりに考えて結論を出してみたかったので、今回考察しました。



考察した結論

結論から申し上げますと、
「基本的には、Base64エンコーディングを用いて、画像をCSSに含むことが良い」と考えました。

特に、ユーザーアクションを促すための画像(ボタンの背景画像など)は、CSSに埋め込んでおくべきと思いました。 ただし、CSSファイルのサイズが100KB以上(感覚値ですが)になる場合には、画像とCSSを分離して、体感速度の低下を防ぐ必要もあるかもしれません。

また上記の結論が絶対という訳ではなく、CSSに含める画像の重要度が低い場合や、初期表示速度をすごく重視したい場合には、 Sprite画像を利用する方が良い場合もあると思いました。


その結論に至った過程を以下に記述したいと思います。



前提知識

SpriteやBase64という話が出ていますが、その用語説明を簡単に記載したいと思います。

画像のSprite化とCSSからの利用方法

複数のアイコン画像(右矢印画像、三角画像など)を1枚の画像にまとめたものをSprite画像といいます。
例えば以下のような画像です。
画像

複数の画像を1枚にまとめることで、画像を取得するサーバーへのリクエスト回数が減り、表示速度の向上が見込めます。
1枚の画像の中にある複数の画像を、それぞれのCSSで使うには、例えば以下のように実装します。
.icon01 {
    background-image: url('sprite.png'); 
    background-position: 0px 0px;
}
.icon02 {
    background-image: url('sprite.png'); 
    background-position: -50px 0px;
}


画像をBase64エンコードしてCSSに埋め込むとは

画像などのバイナリーデータをBase64エンコード(詳しくは、wikipedia参照)することで、 文字列として扱うことができます。
その文字列を、background-imageなどに指定することで、画像を表示する技術をここでは意味します。
Base64エンコードした結果は、例えば以下のような文字列となります。
data:image/png;base64,iVBORw0KGgoAAAAN

上記の文字列を以下のようにCSSに指定することで、画像を表示することが可能です。
.bg-button01 {
    background-image: url('data:image/png;base64,iVBORw0KGgoAAAAN');
}

上記の例では、Base64エンコードされた文字列がCSSの中に埋め込まれています。
このようにして、画像をCSSに含めることが可能です。



Base64のメリット・デメリット

Base64を使う場合に、以下のようなメリットでメリットがあります。

メリット
  • CSSプリプロセッサのScss(のフレームワークであるCompass)などを使うと、 簡単にCSS内にBase64エンコードした画像を書き出すことができ、開発が楽。
  • CSSファイルサイズが大きくなりがちで、読み込むと画像ロードも完了するため、画面表示で最初から画像が表示される。 そのため、ユーザーアクションを促す画像(ボタンの背景画像など)の表示に適する。
  • 運用時の画像キャッシュ更新は、CSSのキャッシュ更新をすることで容易に行うことができる。
  • 画像がCSS内にあるため、画像を取得するためのサーバーへのリクエスト回数が減り、サーバー負荷が下がる。 キャッシュ中のNotModifiyなどのチェックリクエストなどもない。
デメリット
  • base64エンコーディングでは、画像サイズが135%前後大きくなる。 しかしこれは、cssをgzip化して配信することで、CSS全体のファイルサイズを30%前後の圧縮ができ、最終的にはトントン。
  • CSSの読み込み時間がかかるので、(キャッシュがない場合の)初期表示に時間がかかる。
  • CSSを少しだけ更新した場合に、更新していない画像分もロードする必要があり、 CSSの更新回数の多いサイトでは、体感的に遅いと感じられる場合がある。



画像をSprite化してその画像をCSSで指定する場合のメリット・デメリット

続いて、Sprite化した場合のメリットでメリットです。

メリット
  • CSSがBase64に比べて大変軽量となり、その結果初期表示がBase64に比べて速い。
  • CSSの更新と画像の更新を分離することができる。
デメリット
  • Sprite画像を作成するのが面倒だったりする。
    ただしScssのCompassの機能などを使うと、簡単にSprite画像とそれに関するCSSの出力ができる。
  • (PNGの場合)複数画像を1つのファイルとすることで、色数が増えて、圧縮効率が悪くなることが多く、 減色作業などでもファイルサイズの低減量が少なくなる。
  • Sprite画像のロードが完了するまでは、ページに画像が表示されない。
    ユーザーアクションを促す画像(ボタンの背景画像など)は、画像ロードされるまで、そのエリアがボタンだと気づかれない可能性がある。



上記をふまえた考察

Base64とSprite化と、それぞれメリット・デメリットあります。
ただ、今回議論の対象としている「アイコンやボタンの背景画像」に関していえば、Base64でCSSに埋め込む方が良いかなぁと思いました。 初期ロード完了時に、ボタンやアイコンなども完全に表示されている方が(個人的には)カッコいいと思うし、開発も楽だし。

しかしファイルサイズには注意を図る必要があります。 初期ロードが重たいサイトを待ってくれるユーザーなんて皆無かと思いますので。。
ファイルサイズの点では、個人的には1ページ300KB以下(HTML,CSS,JS,画像などすべて含む)を目指すといいかなと思っています。
それより重いと、(特にスマホなど弱小機器では)ロード時間が長くなる気がします。

ファイルサイズが大きくなる場合には、Spriteの併用/デザインの簡略化/CSS3の活用などを行い、軽量ながら良いデザインのサイトを作る必要がありそうです。
デザイナーさんと仕事をしている感覚では、ページの高速化やCSS3による可能なデザインの知識をデザイナーさんと共有することで、いい感じに仕事が進められるように感じています。




最後に

上記の考察が間違ってるよーとか、結論違くない?とか感じる方も多いかも知れません。
もし間違っている箇所があれば指摘いただけると幸いです。
今回考察した内容をもとに、今後のプログラミングを行っていきたいと思います。


さて余談ですが、最近フロントエンドエンジニアで流行ってる(自分の周りだけ?)「ベストプラクティス」という言葉があります。
例えば、「JavaScriptではできるだけグローバル変数を使わない」などのノウハウを指す言葉です。

この言葉は、多くの問題に良い回答を提示しますが、個人的には好きではありません。
ベストプラクティス(=ノウハウと言い換えます)に従えば問題を解決できるという姿勢は、裏返せば正論にしがみついているような気がするから。
ベストプラクティスは、本当に「ベスト」なのでしょうか?他にも良い解法がある気がいつもします。

ただし、ベストプラクティスをたくさん学ぶことは大変重要なことだと感じています。「守破離」の「守」にあたる部分だと考えているからです。

今回記述した考察も、ベストプラクティスな訳ではなくて、1つの意見です。
たくさんの疑いの目で見ていただけると幸いです。

以上長々となりましたが、終わりにしたいと思います。
最後までありがとうございました。





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。