CSSの小技として、普段は隠れているけどマウスカーソルを合わせると表示されるメニューを実現する方法です。
ポップアップメニューとは、見出し部分をマウスでポイントすると、その下にメニュー本体が表示されるようになっているメニューの事です。
結構多くのサイトで見掛けるものですが、多くの場合、これらはJAVAスクリプトで実現しております。
ですが、今日のCSSの仕様に従ったブラウザであれば、CSSだけでも充分実用的なものを作る事は可能です。
今回はそれに挑戦してみましょう。
CSSのセレクタには、hover擬似クラスセレクタがあります。
:hover擬似クラスは、マウスでポイントされている状態を対象とする擬似クラスです。
これを直下セレクタや隣接セレクタと組合わせたセレクタを用いる事で、ある箇所をポイントしている場合に限って表示させると言うようなスタイル指定が可能になります。
しかし、以下のような機能はCSSだけでは実現出来ません。
例えば、見出し部分をポイントすると、メニューがスルスルと出て来るようなものは、CSSだけでは実現出来ません。
動きを実現しようとすると、どうしてもJAVAスクリプトを利用する必要があります。
つまり、CSSだけでは表示/非表示の切替くらいしか出来ないと言う事になります。
当サイトで制作者は事あるごとに口酸っぱくして申し上げている事ですが、対応出来ない環境を切り捨てないようにしましょう。
ポップアップメニューの場合、ポップアップしない環境であっても、最低限のナヴィゲーションを用意するようにします。
ただ、この場合、メニューバーに並ぶ見出し部分にアンカーを設けておけば、それが最低限のナヴィゲーションとして利用出来るようにする事が出来る筈です。
試しに、PC環境の
などでご覧の方は、以下の実験サイトにアクセスしてみてください。
尚、インターネットエクスプローラ 6.0専用のJAVAスクリプトを併用した例は、以下のページで公開実験を行っております。
こちらは、ウィンドウズ版インターネットエクスプローラ 5.0〜6.0でもポップアップメニューの表示が可能です。
それでは、CSSを用いて実現するポップアップメニューについて、実例を交えて解説してみたいと思います。
今回のポップアップメニューの条件は以下のようになります。
CSSのポジショニングを活用する事で、前後関係に関係なく位置を決め打ちする事が可能になります。
センタリングなどの場合には、
必要があります。
後者はファイヤーフォックス 2.xまでなど、比較的新しいブラウザでも対応していない場合があるため、前者のスクリプトでの位置調整が必須となります。
その点、左寄せであれば、多少旧いブラウザでも対応出来るfloatプロパティが使えるので、簡単にブロックを横に並べる事が出来るようになります。
ポップアップさせたメニュー内に、ポイントする事で子メニューが右に現われるようにします。
これを実現するのは難しそうですが、HTMLでのメニューの記述に規則性を与えれば意外に簡単に実現出来るのです。
最近では見出しをポイントすると、スルスルと時間をかけてメニューが出て来るポップアップメニューも見掛けますが、ポップアップメニューに関してCSSだけでは出来ない事でも述べた通り、そう言う動きを持たせたものはCSSだけでは実現出来ません。
ポップアップメニューを実現するためのHTMLは以下のように書きます。
MENU_NAVI)とします。但し、ポップアップメニューに子メニューを含める場合には、以下のようにします。
つまり、メニューバーの見出しとメニュー本体と同様に記述する事となります。
つまり、<ul>要素の内容となる<li>要素は、どの階層であっても
のいずれかと言う事となります。
具体的なポップアップメニューのマークアップのパターンは、以下のようになります。
<ul id="MENU_NAVI"><li><p>第一項目の見出し</p><ul><li><a href="…">第一項目のメニュー1</a></ul><li><a href="…">第一項目のメニュー2</a></ul>…<li><p>子メニューへの見出し</p><ul><p><a href="…">第一項目子メニュー1</a></p><p><a href="…">第一項目子メニュー2</a></p>…</ul></li></ul><li><p>第二項目の見出し</p><ul><li><a href="…">第二項目のメニュー1</a></ul><li><a href="…">第二項目のメニュー2</a></ul>…</ul></lip>…</ul>
スタイル定義自体は実に単純で、
ようにするだけです。
ですが、メニューのスタイルがちょっと複雑ですので、スタイル定義はちょっと長くなります。
また、隣接セレクタや直下セレクタなどが使えれば記述もより単純になるのですが、インターネットエクスプローラ 6.xまではこれらのセレクタが認識出来ないので、なるべく使わないように記述します。
@charset "shift_jis";/* メニューバー全体。 */ul#MENU_NAVI {width: 98%;height: 1.7em;background: #030;position: absolute;left: 0;top: 80px;margin: 0 0 0;padding: 0 0 0 2%;}/* メニューバー内のアンカー。 */ul#MENU_NAVI a,ul#MENU_NAVI a:link,ul#MENU_NAVI a:visited {text-decoration: none;font-weight: bold;color: #fff;font-family: "MS UI Gothic", sans-serif;}/* ポップアップメニュー内のアンカー。 */ul#MENU_NAVI ul a,ul#MENU_NAVI ul a:link,ul#MENU_NAVI ul a:visited {font-weight: normal;color: #000;}/* メニューバー内の各項目。 */ul#MENU_NAVI li {float: left;display: block;background: transparent;list-style-type: none;width: 9em;margin: 0;padding: 0;line-height: 1.2em;/* 更に下位に子メニューがある場合にその表示位置を決めるためのポジショニング指定。 */position: relative;top: 0;left: 0;}/* メニューバー内の各項目の見出し。 */ul#MENU_NAVI li p {display: block;background: #030;margin: 0;padding: 0.025em 0.1em;white-space: nowrap;overflow: hidden;z-index: 1;font-family: "MS UI Gothic", sans-serif;line-height: 1em;}/* ポップアップメニュー本体。 */ul#MENU_NAVI li ul {display: none;width: 11.25em;background: transparent;margin: -3em 0 0;/* 上下にパディングを付ける事で、カーソルがちょっとはみ出した場合にも消えないようにする。 */padding: 3em 0 3em;border: none;font-size: 100%;z-index: 100;white-space: normal;overflow: visible;/* 上パディング分ずらす。 */position: absolute;top: 1.7em;left: 0;}/* ポップアップメニュー本体内の、更に下位のポップアップメニュー。 */ul#MENU_NAVI li ul li ul {position: absolute;top: -3.0em;/* 元のポップアップメニューの表示位置に合わせてずらす。 */left: 11.25em;/* 元のポップアップメニューより右にずらす。 */margin: 0 0 0 1px;padding: 3em 3em 3em 0;width: 11.25em;}/* ポップアップメニュー内の各項目。 */ul#MENU_NAVI li ul li {float: none;display: block;list-style-type: none;margin: 0;padding: 0;position: relative;top: 0;left: 0;background: #fff;white-space: normal;font-size: 80%;line-height: 1em;}/* ポップアップメニューの更に下位にある子メニューで 文字の大きさが小さくならないようにするための措置。 */ul#MENU_NAVI li ul li ul li {font-size: 100%;}/* ポップアップメニュー内の各項目は原則として<p>要素か<a>要素とする。 */ul#MENU_NAVI li ul li p,ul#MENU_NAVI li ul li a {display: block;width: 10.44em;margin: 0 0 -1px;padding: 0.4em;border: 1px solid #999;line-height: 1.2em;background: #fff;color: #000;white-space: normal;}/* ポップアップメニュー内の各項目で<a>要素を含んだ<p>要素とした場合の調整。 */ul#MENU_NAVI li ul li p a {margin: -0.4em;padding: 0.4em;border: none;}/* ポップアップメニュー内の各項目内のアンカーをポイントしているときのスタイル。 */ul#MENU_NAVI li ul li a:hover {color: #000;background: #afc;}/* 子メニューがある事を示す目印。 */ul#MENU_NAVI li ul li p a:before {float: right;color: #0c0;content: "\2794";/* 右向きの太い矢印のUCSコード。 */font-weight: bold;margin: 0;padding: 0;}/* ポップアップメニューが表示となる場合。 */ul#MENU_NAVI>li:hover>p+ul,ul#MENU_NAVI>li li:hover>ul,ul#MENU_NAVI>li li>ul:hover {display: block;}/* IE 6でのスタイル補正 ※IE 6では、 <?xml ?>宣言のあるXHTML文書では非標準レンダリングとなるため、 widthプロパティ値を補正する必要がある。 */* html ul#MENU_NAVI li ul li p,* html ul#MENU_NAVI li ul li a {width: 11.25em;margin-top: -1px;margin-bottom: 0;}* html ul#MENU_NAVI li ul li p a {width: 11.25em;margin: -0.4em;}* html ul#MENU_NAVI ul ul {left: 11.0em;width: 11.25em;}
ここでは重要と思われる点を中心に解説して行きましょう。
メニューバー全体のスタイル定義については、文書内の指定された位置に、横幅一杯に描画します。
CSSの標準では、widthプロパティの値には左右のborder-widthプロパティ及びpaddingプロパティの値は算入されない決まりですので、widthプロパティの値は当然左パディング分を差引いた値となります。
メニューバー内各項目のスタイル定義については、floatプロパティを駆使して左から項目を横方向に並べて行きます。
インラインブロック或いはインラインテーブルなどは、少し前のヴァージョンのブラウザで認識されないため、フローティングはブロックレヴェル要素をインライン風に(横に)並べるのに今も便利に使える機能です。
ところで、最後の方にはポジショニング指定が書かれております。
この指定は表示位置を全く動かしていないので意味が無いように見えるかも知れません。
しかし、この結果、<li>要素の下位でposition: absolute; プロパティを与えられた要素(今回の場合はポップアップメニューや子メニューとなる<ul>要素のみ)のポジショニング基準が上位の<li>要素基準となり、従って
と言った位置指定が出来るようになります。
メニューバー内の各項目見出しのスタイル定義については、メニューバーの部分に綺麗に掛かるように工夫します。
フローティングを行うため、widthプロパティで具体的な幅を取っております(※1)が、そのため見出しとなる文字列が長過ぎる場合に問題が生じ得ます。
white-space: nowrap; プロパティで入り切らない場合でも折り返しをしないようにして、更にoverflow: hidden; プロパティではみ出した部分を見えないようにします。(※2)
ポップアップメニュー本体のスタイル定義については、ポジショニングを用いて見出し部分の真下に来るようにすれば良いのですが、ここではちょっとした工夫をしております。
それは、ポップアップメニュー本体の上下に三文字分のパディングを与えていると言うものです。
何故こんな事をしたのかと申しますと、こうする事で閲覧者の手が滑ってポップアップメニュー部分からマウスカーソルがちょっとはみ出してしまった場合でもすぐには消えないようにしたかったからです。
パディング部分も要素の領域の一部ですのでこの範囲にカーソルが納まっている限りはCSSでの処理で消えてしまう事はありません。
尚、パディングを与えた事で、
と言う副作用が生じますが、利便性を優先したかったのでこのようにしております。
また、この段階ではdisplay: none; プロパティを用いて非表示となるようにしておきます。
ポップアップメニュー本体内の更に下位のポップアップメニュー、すなわち子孫メニューのスタイル定義については、ポップアップメニュー本体とポジショニングの位置を除けば特に代わる部分はありません。
ですので、
この二点に注意すればよいでしょう。
ただ、それだけでは芸がないので、利便性を高めるためのパディングについて、子孫メニューの場合には上下だけでなく右側にも三文字分与える事とします。
ポップアップメニュー内の各項目のスタイル定義自体には特に細かく解説する必要はないと思いますが、二つほど注意点を与えておきます。
一つは、インターネットエクスプローラ 7.0まででは、<a>要素にdisplay: block; プロパティを与えても、横幅をきちんと指定しておかないと、文字のある部分以外をポイントしてもアンカーとして機能しない場合がある事です。
ですので、ポップアップメニュー内の<a>要素にはwidthプロパティで値を指定しておく必要があります。
もう一つとしては、ポップアップメニュー内で子メニューを開ける<p>要素内にアンカーがある場合、マージンとパディングを調整する必要があります。
子メニューがある事を示す目印のスタイル定義については、:before擬似要素セレクタとcontentプロパティで右を差す太い矢印 ➔ を右にフロートさせます。
ポップアップメニューが表示となる場合のスタイル定義については、以下の点に留意してセレクタを決めました。
更に重要な事として、
必要があります。
つまり、表示させるスタイル定義が原因で、普段も表示されっ放しになってはいけないと言う事です。
この場合、ポップアップメニューの普段の表示スタイルのセレクタと、表示となる場合のスタイル定義では、セレクタの詳細度が後者のほうが高いため、表示となるような状況以外では常に非表示となるように出来ます。
IE 6でのスタイル定義補正については、以下の点に留意します。
今回対象としているHTML文書は、<?xml ?>宣言を持ったXHTML文書ですので、非標準のレンダリングとなります。
具体的には、要素のwidthプロパティには、左右のborder-widthプロパティ及びpaddingプロパティが算入された値となります。
このため、スタイルを調整する必要があります。
インターネットエクスプローラ 6.0まででのみ有効なスタイルにするには、セレクタを * html の下位要素のセレクタとします。
尚、ご承知の通り、<?xml ?>宣言を持ったXHTML文書以外に、
でも非標準レンダリングとなります。
また、インターネットエクスプローラ 6.0まででは、このCSSだけではどう頑張ってもポップアップメニューを表示させる事が出来ないため、
のいずれかを採る事となります。
前者の場合、スクリプトが使えない場合の事も考慮する必要があります。
また、いずれの場合であっても、ポップアップメニューが使えない事で閲覧者に不便を強いるような事はあってはなりません。
つまり、代替となるナヴィゲーションをどこかに設置するなどの工夫が必要となります。
本URLで平成21年10月31日まで公開していた旧版との違いについて書いておきます。
メニューは左寄せに限定(右寄せでも良いのですが稀に崩れる事があります)、センタリングはCSSだけでは出来ません。
実際に本記事で解説したスタイルシート等をお使いになる場合、恐らくそのままのスタイルでご利用になる事は先ずないと思われます。
ですから、当然何らかの改変を行う事と思われますが、その際のヒントを挙げておきます。
色や背景或いは余白などを好みに合わせて修正する事になると思いますが、その場合完成するまではスタイルシート内にある display: none;はコメントアウトしておく事をお勧めします。
これに依り、ポップアップされるであろう全メニューが消えずに表示されたままになりますので、それをブラウザで確認しながら適宜修正を施して行くと言う訳です。
完成したら、コメントアウトを解いて、正しくポップアップするかを確かめましょう。
試験出来る環境があれば、対応するのも悪くはないでしょう。ですが、その際には普通のブラウザで返っておかしな結果になる恐れがありますので、以下のブラウザハックを活用してインターネットエクスプローラ 6.0まで及び7.0だけで適用されるスタイルにするようにしてください。
セレクタについて、* html の下位要素セレクタにします。
例えば、ul#MENU_NAVI li にインターネットエクスプローラ 6.0まで専用のスタイルを当てたい場合には、 * html ul#MENU_NAVI li と言うセレクタを用います。
このセレクタはCSSの文法上問題はないものですが、HTMLの文法上あり得ない要素となるため、他のブラウザでは無効となります。
セレクタについて、*+html の下位要素セレクタにします。
例えば、ul#MENU_NAVI li にインターネットエクスプローラ 7.0専用のスタイルを当てたい場合には、 *+html ul#MENU_NAVI li と言うセレクタを用います。
このセレクタもCSSの文法上問題はないものですが、HTMLの文法上あり得ない要素となるため、他のブラウザではやはり無効となります。
また、インターネットエクスプローラ 6.0まででは、JAVAスクリプトを併用する事でポップアップ出来るようになる代わりに崩れが生じる事もあります。
どうしても対応が困難であれば、最低限のナヴィゲーションを提供するレヴェルにしても仕方はないかも知れません。
尚、ウィンドウズ環境をお持ちの方なら、IEテスタが便利ですが、このソフトは非常にクラッシュし易いので、マルティプルIEを利用する手もあります。