Google Chrome または Safari を使用される事を強くお薦めしますw
他のブラウザでは Javascript の処理が重いです(汗)


2010/08/31

ロールオーバーいろいろ

ちょっとはお役に立ちそうな話もしてみますw

ロールオーバー、すなわちマウスポインターが上に来ると画像が変わるって奴は、誰もがやりたがり(そうか?)あちこちにその手法が書かれてたりするのだけれど、メジャーどころをまとめるとこんな感じ。

【その1:画像再読込】
最も簡単な方法。
マウスが上に乗ったときのコールバック onmouseover と上から外れたときのコールバック onmouseout でそれぞれ違う URL を src 属性につけてやります。

<div>
  <img src="hoge_out.gif" id="rollover">
</div>

みたいなのに対し、こんなスクリプトを用意します。

var img = document.getElementById('rollover');

img.onmouseover = function() {
    img.src = 'hoge_over.gif';
}

img.onmouseout = function() {
    img.src = 'hoge_out.gif';
}

これをやってみた結果がこちら:



こいつの欠点はマウスを乗せた時の画像 hoge_over.gif が、実際にマウスを乗せるまで読み込まれないこと。
従って、マウスを乗せた最初の1回は画像が出るまで時間がかかってしまいます。
(2回目以降はブラウザにキャッシュされてるので早い)

そこであらかじめマウスを乗せたときの画像も読み込んで置くのが望ましいです。いわゆる「先読み」ですね。
最も簡単なのは HTML 側で 幅も高さも1ピクセルの極小画像として表示しておくことです。
つまりこんな感じ。

<div>
  <img src="hoge_out.gif" id="rollover">
  <img src="hoge_over.gif" width=1 height=1>
</div>

実際にはページの一番下とか目立たない場所に表示させておきます。

やだ、こんなのダサい、と思うなら、javascript で先読みさせておくというのもできます。

var imgDummy = new Image;
imgDummy.src = 'hoge_over.gif';

これだとどこにも表示されませんが、読み込みだけは行われてます。

これらの先読み方法は、ブラウザが画像をキャッシュするということを利用してます。実際に先読みした画像はどこにも使用されないんだけど、後で同じ URL を指定されることでブラウザがそのキャッシュを使ってくれるのです。

そうじゃなくて、読み込ませた画像はそのまま使いたいというなんとなく貧乏性な方(俺や!)には、次の方法を。

【その2:片方を非表示にする】
2つの画像をぴったり重ねて置いておいて、片方を非表示にします。
ぴったり重ねるために position: absolute を指定する必要があります。
また、非表示の画像に対してイベントは発生しないので、画像を div の中に配置して、その div に対するイベントを定義することになります。

<div id="rollover">
    <img id="img_over" src="hoge_over.gif">
    <img id="img_out"  src="hoge_out.gif">
</div>

css でいろいろ定義

#rollover {
    position:relative;
    width:   50px;
}

#img_over {
    position:absolute;
    top:     0px;
    left:    0px;
    display: none;
}

#img_out {
    position:absolute;
    top:     0px;
    left:    0px;
}

で、javascript はこんな風。

var div      = document.getElementById('rollover');
var img_out  = document.getElementById('img_out');
var img_over = document.getElementById('img_over');

div.onmouseover = function() {
    img_out.style.display = 'none';
    img_over.style.display = '';
}

div.onmouseout = function() {
    img_out.style.display = '';
    img_over.style.display = 'none';
}

やってみた結果がこちら:






お気付きだと思いますが、display 属性を変更する代わりに z-index を使って、片方の画像をもう片方より上に表示するというのでも構いません。

管理する上で画像ファイルがいくつもあるのはイヤん、という方もいると思います。
ボタン系の画像をまとめてどかんと1枚にできれば読み込みも1回だし管理もしやすいかもしれません。
それが第3の方法。

【その3:背景画像にする】
これはちょっとしたコロンブスの卵です。略してコロたま。略さんでもいいけど。
まず div を用意します。

<div id="rollover"></div>

css で大きさと背景画像を指定します。
#rollover {
    position:  relative;
    width:     50px;
    height:    50px;
    background:url('hoge.gif');
}

ここで背景画像 hoge.gif は通常の画像とロールオーバー時の画像を並べた1枚の画像として作っておきます。
並べる方向は縦でも横でもいいけど、ここでは横にならべてみました。
こんな画像になります。


これでどうするかというと、ロールオーバー時に背景の表示位置を横にずらしてやるわけです。
つまりイベント発生時に background-position を書き換えてやるのですな。
var div = document.getElementById('rollover');

div.onmouseover = function() {
    div.style.backgroundPosition = '-50px 0px';
}

div.onmouseout = function() {
    div.style.backgroundPosition = '0px 0px';
}
指定するのは画像の左上位置なので、右側の絵を表示するためにマイナスの値を設定しています(背景全体を左にずらしてます)。
やってみたのがこちら:

↑背景なので右クリックしても「画像を保存」のメニューがでません。

ボタンがいっぱいあるなら、全部並べた1枚の画像にして、どの div もそれを背景とし、状況に応じて background-position を変更してやれば良いです。

今製作中のゲームでもこのテクニックを使ってます。
キャラクターが歩くときに、1コマずつ画像ファイルを用意するのが面倒なんで、こんな風に上下左右4方向でそれぞれの方向に3コマ定義した画像ファイルを div の背景にしてます。

div の位置を変更しながら、背景の表示位置も変えてやることでとことこ歩きます。こんな感じ。


他にもいろいろ応用ができそうです。例えば数字を縦にずらずらと書いた背景画像を少しずつずらしていくとスロットマシンになりますね。
もう十分記事が長くなったので書きませんけどw
(2011/01/07追記:この手法には CSSスプライト って名前が付いてたんですね。なるほど。)

3 件のコメント:

syk さんのコメント...

CSSのみでしかやったことなす<ロールオーバー

doradoala さんのコメント...

4回目の書き込み挑戦中・・・。
もし沢山あったら消してください^_^;

(●ω●)AJ さんのコメント...

sykさん>

普通は CSS でやるでしょうねw
ここは javascript の話をしてるんで、CSS で解決!ってのは除外してます。


doraさん>

1個しかないですよ^^
てかなんで書き込みできないんだろ?

コメントを投稿