以前、個人的に作っていたサイトで、なんかメニューの見せ方を工夫できないかなと思って、「prototype.js」 と 「effects.js」 を利用してやってみたのが今回紹介するメニューのサンプル。
マウスオン / オフすると、隠れているサブメニューが滑らかに閉じたり開いたりします。クリックで開いたり、折りたたまれたりするメニューはよくありますが、それに無駄なエフェクトを施した版といったところ。
実際に動作しているサンプルはこちら。マウスオン / オフで滑らかに開閉しちゃいます。
さて、今回の材料は、
- JavaScript ファイル 3種
- 本メニューの HTML ソース
- 本メニュー用 CSS の追加
JavaScript ファイルはマウスオン、オフ時の動きを制御するために使用。これは 「PJ Hyett」 で公開されている 「Timeout your Mouseovers」 をカスタマイズ。 「Timeout your Mouseovers」 はマウスオーバーのタイムアウトを利用してロールオーバーアクションを制御してくれるスクリプト。
以前紹介した、「小技の効いた 「ブックマークに追加」 ボタン」 でもベースに使用させてもらったやつです。
上記をカスタマイズし、「sidemenu.js」 という名前で外部ファイルに。さらに、こいつを動かすために毎度おなじみ 「prototype.js」 と 「effects.js」 という JavaScript ライブラリも別途用意します。
で、上記の材料一式は下記にすべてまとめて置いてありますのでよろしければどうぞ。
では簡単に解説。まず下記が今回のメニューの HTML ソース。わかりやすいように区切りのいいところにコメントを入れています。
<ul id="slidemenu_sample"> <!--menu_1--> <li> <a href="#link01" onmouseout="menu_1.hidePopup('menu_1')" onmouseover="menu_1.showPopup('menu_1')">menu #01</a> <!--menu_1 submenu--> <ul id="menu_1" style="display:none" onmouseout="menu_1.hidePopup('menu_1')" onmouseover="menu_1.showPopup('menu_1')"> <li><a href="#sublink01">submenu #01</a></li> <li><a href="#sublink02">submenu #02</a></li> <li class="bottom"><a href="#sublink03">submenu #03</a></li> </ul> <!--menu_1 submenu end--> </li> <!--menu_1 end--> <!--menu_2--> <li> <a href="#link02" onmouseout="menu_2.hidePopup('menu_2')" onmouseover="menu_2.showPopup('menu_2')">menu #02</a> <!--menu_2 submenu--> <ul id="menu_2" style="display:none" onmouseout="menu_2.hidePopup('menu_2')" onmouseover="menu_2.showPopup('menu_2')"> <li><a href="#sublink04">submenu #04</a></li> <li><a href="#sublink05">submenu #05</a></li> <li class="bottom"><a href="#sublink06">submenu #06</a></li> </ul> <!--menu_2 submenu end--> </li> <!--menu_2 end--> <!--menu_3--> <li class="bottom"> <a href="#link03" onmouseout="menu_3.hidePopup('menu_3')" onmouseover="menu_3.showPopup('menu_3')">menu #03</a> <!--menu_3 submenu--> <ul id="menu_3" style="display:none" onmouseout="menu_3.hidePopup('menu_3')" onmouseover="menu_3.showPopup('menu_3')"> <li><a href="#sublink07">submenu #07</a></li> <li><a href="#sublink08">submenu #08</a></li> <li class="bottom"><a href="#sublink09">submenu #09</a></li> </ul> <!--menu_3 submenu end--> </li> <!--menu_3 end--> </ul>
ソースを見ていただければ、まあなんとなくわかるんではないかと。JavaScript はイベントハンドラとして、「onmouseout」、「onmouseover」 を使用していますが、これだとキーボード操作には反応しないので、「onblur」、「onfocus」 を合わせて指定してあげた方が本当は親切かも。(今回は省略)
ところどころについている、「class="bottom"」 の記述は、サブメニュー内の一番最後の li 要素、及び一番最後のメニューの ul 要素に必須です。(赤字の部分)
お次が CSS のサンプルソース。これは別に難しいことないですね。
* { margin:0; padding:0; } ul { list-style:none; } ul#slidemenu_sample { border:1px solid #35b3d1; overflow:hidden; } ul#slidemenu_sample li { border-bottom:1px solid #35b3d1; } ul#slidemenu_sample li.bottom { border:none; } ul#slidemenu_sample li a { display:block; padding:5px 0 5px 10px; text-decoration:none; width:100%; } ul#slidemenu_sample li a:hover { color:#fff; text-decoration:none; background:#35b3d1; } ul#slidemenu_sample li ul { border-top:1px solid #35b3d1; } ul#slidemenu_sample li ul li { background:#eee; }
最後が JavaScript ファイル、「slidemenu.js」 の中身。見ての通り、ほぼ同じことをメニュー項目の数だけ書いているわけです。もっとすっきりかけるような気もしますが、あまり気にしない。
/*------------------------- menu_1 -------------------------*/ var menu_1 = { timeout : null, showPopup : function(){ clearTimeout(this.timeout); if($('menu_1').style.display == 'none'){ this.timeout = setTimeout(function(){new Effect.BlindDown('menu_1', {duration:.3, fps:40})},400); } }, hidePopup : function(){ if($('menu_1').style.display == 'none'){ clearTimeout(this.timeout); }else{ this.timeout = setTimeout(function(){new Effect.BlindUp('menu_1', {duration:.3, fps:40})},300); } } } /*------------------------- menu_2 -------------------------*/ var menu_2 = { timeout : null, showPopup : function(){ clearTimeout(this.timeout); if($('menu_2').style.display == 'none'){ this.timeout = setTimeout(function(){new Effect.BlindDown('menu_2', {duration:.3, fps:40})},400); } }, hidePopup : function(){ if($('menu_2').style.display == 'none'){ clearTimeout(this.timeout); }else{ this.timeout = setTimeout(function(){new Effect.BlindUp('menu_2', {duration:.3, fps:40})},300); } } } /*------------------------- menu_3 -------------------------*/ var menu_3 = { timeout : null, showPopup : function(){ clearTimeout(this.timeout); if($('menu_3').style.display == 'none'){ this.timeout = setTimeout(function(){new Effect.BlindDown('menu_3', {duration:.3, fps:40})},400); } }, hidePopup : function(){ if($('menu_3').style.display == 'none'){ clearTimeout(this.timeout); }else{ this.timeout = setTimeout(function(){new Effect.BlindUp('menu_3', {duration:.3, fps:40})},300); } } }
設置の際は、まず HTML ファイルの <head> ~ </head> 内に 3つの JavaScript ファイルを読み込みます。
<script src="/js/slidemenu.js" type="text/javascript"></script> <script src="/js/prototype.js" type="text/javascript"></script> <script src="/js/effects.js" type="text/javascript"></script>
あとは HTML ソースをそのままコピペ。CSS を当ててやれば完成。簡単です。無事に動作したら、そこから先はご自由にカスタマイズしてみてください。
ちなみに、このメニューの最大の難点は、JavaScript が 「OFF」 で CSS が 「有効」 の場合にサブメニューが表示されないということ。あと、根本的なところでエフェクト自体が見た目だけの無駄な動きなので、ユーザビリティ / アクセシビリティを気にする場合は使いどころにお気をつけください。
なお、Firefox、Opera9、IE6、IE7 では動作確認していますが、その他の古いブラウザは知りません。あと毎度ながら Mac はさっぱりなので、もし Mac 使いの方がいましたら確認お願いします。(他力本願)