img要素を使ったCSSロールオーバー+α

画像をリストで配置したグローバルナビゲーションにロールオーバーを設定する時の話。JavaScriptを使わずCSSだけで実現するロールオーバーはいくつかやり方があると思いますが、以下のパターンをよく使っています。

パターン1

完成イメージ

パターン1のスクリーンショット

デモ

img要素を使ったCSSロールオーバー+α デモ1

XHTML

<ul id="globalNav">
<li><a href="#"><img src="/img/nav1.gif" alt="ナビ1" /></a></li>
<li><a href="#"><img src="/img/nav2.gif" alt="ナビ2" /></a></li>
<li><a href="#"><img src="/img/nav3.gif" alt="ナビ3" /></a></li>
<li><a href="#"><img src="/img/nav4.gif" alt="ナビ4" /></a></li>
<li><a href="#"><img src="/img/nav5.gif" alt="ナビ5" /></a></li>
</ul>

CSS

#globalNav {
height: 30px; /* ナビ画像の高さ */
background: url(nav_active.gif) no-repeat 0 0;
overflow: hidden;
}
#globalNav li {
float: left;
width: 90px;
}
#globalNav li a {
display: block;
*zoom: 1; /* ie6,7 */
}
#globalNav li a:hover,
#globalNav li a:active {
text-indent: -9999px;
}

全てのナビがロールオーバーした状態の画像を用意し、#globalNavの背景に設定します。

パターン1 スライスを切る様子

li要素に明示的な幅指定を行っておき、その子であるa要素にdisplay:block;を設定。
a:hover時にtext-indent:-9999px;を設定することでimg要素を画面外に飛ばし、背景画像を見せることでロールオーバーさせています。

この手法の欠点は、各ボタンを格納するli要素に明示的に幅を指定しないと意図した表示にならないという点。仮に、各ボタンの横幅が異なっている場合、各li要素にclassとかidを振って別々の幅を指定してやらないといけないということになります。

パターン2

各ボタンの横幅が異なっているけれど、各li要素にclassやidを書きたくない場合・・・このシチュエーションって結構経験していて悩んでいたのですが、どうにか実現することができたのがこのパターンです。

XHTMLはパターン1と同じとして。

完成イメージ

パターン2のスクリーンショット

デモ

img要素を使ったCSSロールオーバー+α デモ2

XHTML

<ul id="globalNav">
<li><a href="#"><img src="nav_products.gif" alt="ナビ1" width="82" height="18" /></a></li>
<li><a href="#"><img src="nav_gallery.gif" alt="ナビ2" width="64" height="18" /></a></li>
<li><a href="#"><img src="nav_blog.gif" alt="ナビ3" width="39" height="18" /></a></li>
<li><a href="#"><img src="nav_about.gif" alt="ナビ4" width="56" height="18" /></a></li>
<li><a href="#"><img src="nav_contact.gif" alt="ナビ5" width="71" height="18" /></a></li>
</ul>

CSS

#globalNav {
height: 18px; /* ナビ画像の高さ */
overflow: hidden;
background: url(nav_active.gif) no-repeat 0 0;
font-size: 10px;
}
#globalNav li {
float: left;
margin-right: 20px;
*zoom: 1; /* ie6,7 */
}
#globalNav a {
display: -moz-inline-box;
display: inline-block;
*zoom: 1; /* ie6,7 */
vertical-align: bottom;
}
#globalNav a:hover,
#globalNav a:active {
padding-top: 9999px;
}

li要素には幅指定を行いません。そして、右のボタンとの余白をmargin-rightで設定しますが、全てのボタンでこれが同一になるように画像のスライスを調節します。一番右のmarginが領域を飛び出してしまうケースもあると思いますが、その辺は適当にうまくやります。

パターン2 スライスを切る様子

a要素はdisplay:inline-block;になるようにします。 そしてinline-blockなのでvertical-alignの調整も行っておきましょう。 inline-blockについてはCSS Nite in Ginza, Vol.27での小山田さんのセッション(のスライド)が参考になります。

また、img要素にwidth、height属性をそれぞれ明示的に指定をする必要があります。これはFirefox2で正しく表示するために必要です。

そしてa:hoverpadding-topに大きな値を指定して、含んでいるimg要素を追い出すようにしてやれば、完了です。追い出した部分を非表示にするために、#globalNavにheightの明示的な指定とoverflow:hidden;の指定が必要なのでお忘れなく。(この2つはfloat解除の意味合いもありますが)

追記 – 2009-10-28

display:-moz-inline-boxdisplay:inline-blockの順序が逆だったので修正。まぁどちらでも結果オーライなことにはなっていますが、CSS Nite in Ginza, Vol.27 小山田さんのセッション(のスライド)におけるコードを尊重させていただきたいと思います。

追記 その2 – 2009-10-28

Firefox2においての表示不具合への対処について、本文に追記しました。Firefox2で正しく表示するためにはa {display:-moz-inline-box;}とするだけでなく、中に含むimg要素にwidth・height属性の指定を行い、さらにa {vertical-align:bottom;}の指定の2点が必要です。

これらの指定がない場合、Firefox2で初回読み込み時に限って画像が正しく表示されませんでした。ただし2回目の読み込みでは正常な表示だったので、画像がキャッシュされていない状態において幅・高さが検出できないために起こる現象のようです。

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*