Wellcom to my blog!

2009年4月30日木曜日

CSS Spriteの流派をまとめる

Yahoo!ニュースがリニューアルしてレスポンスが速くなったそうですが、高速化手法の中に「CSS Sprite」というものがありました。

いくつかある画像を1つの画像に連結し、CSSにて連結画像の中にある目的部位を切り出して表示しようという技術です。サーバに対するリクエストの数を減らす効果があります。

今日の大嘘 - by edvakf in hatenaもそうですが、Yahoo!ニュースの一部のCSS Sprite画像も余白が多く、「速くする技術使ったよ」というのは説得力に欠けるのですが)



最近よく見るこのヘンテコな技術について調べ、転送の速さだけでなく、利便性を損なわないような形でこの技術を使えないものだろうかと考えました。

ではその成果を生かしてあれこれしようと思いましても当備忘録程度ではサーバにリクエストする画像の数など高が知れています。

そういうわけで、使わない技術はすぐ忘れちゃいそうなので、書き残しておきます。



※以下、Web標準に従っていない記述がありますが、見た目を調整するためなどのささやかな考慮のつもりです。Web標準に従うべきという意見もごもっともですが、あなたが自分でCSS Spriteを使うときにそのように調整して使えばよろしいかと思います。

方法1 imgを用い、topとleftで指定する


CSS


.sprite{
overflow:hidden;/*clip使用時消去*/
position:relative;
}
.sprite img{
position:absolute;
}
#div1{/*clip使用時消去*/
width:32px;
height:32px;
}
#img1{
top:0;
left:-32px;
/*clip:rect(0 64px 32px 32px);*/
}

HTML


<div class="sprite" id="div1"><img src="sample.png" alt="" id="img1" /></div>

解説


imgで材料となる画像をひたすら貼り付け、画像の該当箇所をtopとleftから指定する方法です。

画像サイズの指定のためにdivにidを付けていますが、例えばアイコンのような使用する画像の大きさが決まっている場合にはdivのclassの中に画像サイズの指定を入れてしまえば良いため、その場合には手軽な方法の一つになります。そうでない場合でdivのidをどうしても使用したくない場合、.spriteのoverflow:hidden;を消し、img1にclip:rect(0 64px 32px 32px);などと画像の範囲を指定することで代用可能です。

しかし、GoogleのトップページでスタイルシートをOFFにすれば分かりますが、そういう条件下では要らぬ画像が入ってきて何が何だか分からなくなります。

方法2 スペーサーの背景にする


CSS


.sprite{
background:url(sample.png) no-repeat;/*no-repeatは不要?*/
}
#img1{
width:32px;
height:32px;
background-position:-32px 0;
}

HTML


<img class="sprite" src="space.png" id="img1" alt="SAMPLE" />

解説


方法1のスタイルシートOFF時の画像が煩わしい場合に使える方法です。

悪しき風習、スペーサーPNG/GIFを使用し、画像表示がONになった時のimgの挙動――(imgのsrcを指定しなかった場合の)「altテキストの展開」と「ファイル行方不明のアイコンの表示」を無理矢理避けています。

divなどで囲まなくてもimgのclassとidを駆使して1つの要素だけで機能を実現できるので、コードがとてもシンプルになります。

画像表示OFFの場合はaltテキストが見えるため、そこに何のコンテンツがあるのか推測できますが、スペーサーを置換するような挙動であるためにスタイルシートOFF・画像表示ONの状態では画像があるのかさえ判別できなくなります。

見えないくらいなら方法1のように余計に見えた方が良いと思いますが、この悪い方法を使用しているサイトが少なくとも2つ存在します。

例えば、AmazonのサイトでスタイルシートOFF・画像表示ONにするといくつかのボタンが消えます

方法3 インデントで文字列を画面外に追いやる


CSS


.sprite{
background:url(sample.png) no-repeat;/*no-repeatは不要?*/
display:block;
text-indent:-1000%;
}
#img1{
width:32px;
height:32px;
background-position:-32px 0px;
}

HTML


<span class="sprite" id="img1">SAMPLE</span>

解説


方法2に似ていますが、imgを置いていません。方法2と同じく、コードをシンプルに仕上げられます。

text-indentを使用して背景の上に乗っている文字列を画面外に寄せてしまうというやや強引な方法です。

最近ではYahoo!ニュースで使われましたが、こちらの方法はスタイルシートON・画像表示OFFにするとコンテンツが見えなくなってしまう問題があります。

方法4 文字列のみを消し、背景を残す


CSS


.sprite{
background:url(sample.png) no-repeat;/*no-repeatは不要?*/
}
.sprite span{
display:none;/*visibility:hidden;*/
}
#img1{
width:32px;
height:32px;
background-position:-32px 0;
}

HTML


<div class="sprite" id="img1"><span>SAMPLE</span></div>

解説


divの背景に画像の該当箇所を指定し、spanの文字列をdisplay:noneやvisibility:hiddenで消し去ります。

コードはやや冗長になりますが、考え方がより単純なので方法3よりも初心者向きかもしれません。

効果は方法3と全く同じで、この方法も条件によってコンテンツが見えなくなる問題があります。

方法5 空spanの背景を文字列に被せる


CSS


.sprite{
text-align:center;
vertical-align:middle;
position:relative;
overflow:hidden;
}
.sprite span{
background:url(sample.png) no-repeat;/*no-repeatは不要?*/
position:absolute;
}
#div1{
width:32px;
line-height:32px;
}
#img1{
width:32px;
height:32px;
background-position:-32px 0;
top:0;left:0;/*余白からはみ出ないよう調整*/
}

HTML


<div class="sprite" id="div1"><span id="img1"></span>SAMPLE</div>

解説


テキストが入っていないspanの背景に画像の該当個所を指定し、それを代替となる文字列に被せます。

スタイルシート・画像表示がONになっていようとOFFになっていようとそれなりにコンテンツを認識させてくれます。

透明な余白がない画像に対して真価を発揮しますが、そうでない場合、spanにある文字列がはみ出すことがあります。

方法6 spanを画像に置き換える


CSS


.sprite{
position:relative;
}
.sprite span{
content:url(sample.png);
position:absolute;
}
#img1{
left:-32px;
top:0;
clip:rect(0 64px 32px 32px);
}

HTML


<div class="sprite"><span id="img1">SAMPLE</span></div>

解説


方法3・方法4とほぼ同じ効果がある方法です。

背景を表示させるのではなく、contentによって文字通り「置き換え」をしています。

コードは冗長になり、分かりやすさも手軽さも劣っていると思われますが、背景としてはでなくimg要素で貼り付けられた画像と同じように処理させるため、例えば右クリックから材料の画像を保存することができるようになるという小さなメリットがあります。

方法7 空spanを画像に置き換えて文字列に被せる


CSS


.sprite{
position:relative;
text-align:center;
vertical-align:middle;
overflow:hidden;
}
.sprite span{
content:url(sample.png);
position:absolute;
}
#div1{
width:32px;
line-height:32px;
}
#img1{
left:-32px;
top:0;
clip:rect(0 64px 32px 32px);
}

HTML


<div class="sprite" id="div1"><span id="img1"></span>SAMPLE</div>

解説


方法5とほぼ同じ効果がある方法です。

backgroundがcontentになり、#img1の部分がごっそり変わったのみという変則になります。

方法6と同じく、画像が背景としてでなくimg要素の画像と同じように処理されるので、右クリックから保存することができるようになります。

追記:方法8 paddingで領域を作り、背景を表示させる


CSS


.sprite{
overflow:hidden;
display:block;
height:0;/*width:0;*/
background:url(sample.png) no-repeat;/*no-repeatは不要?*/
}
#img1{
width:32px;/*height:32px;*/
padding-top:32px;/*padding-left:32px;*/
background-position:-32px 0;
}

HTML


<span class="sprite" id="img1">SAMPLE</span>

解説


livedoorクリップにてforestkさんに「自分が使ってる方法が無かった」という指摘を頂いたため、独自に調査し、作成した例文です。

方法3・4・6と同じ効果がありますが、padding-topやpadding-leftを使うところが特徴的です。

代用可能な変形パターンがあり興味深くはありますが、わざわざこの方法を使う意図は謎です。

条件別、コンテンツの表示に支障がないか表












StyleON & ImageONStyleON & ImageOFFStyleOFF & ImageONStyleOFF & ImageOFF
方法1
方法2×
方法3×
方法4×
方法5
方法6×
方法7
方法8×

0 件のコメント:

コメントを投稿