たくさんのメニューを小さな場所へ収めるのにドロップダウンメニューはもってこいの方法で、
色々とスタイリッシュなライブラリーが出てますが、ドロップダウンするのが1箇所だけだったら自作でもいいんじゃないの?
ってことで簡単にmootoolsでのドロップダウンメニューの作り方を書いてみます。
まずXHTMLソースは次のように、ボタンになるリンクの下(兄弟)にulとかでリストメニューを作り
識別用のIDをボタンに、クラスを子メニューにつけておきます。
1 2 3 4 5 6 7 8 9 10 11 12 | < ul id = "navigation" > < li >< a href = "#" title = "サンプル1" >サンプル1</ a ></ li > < li >< a id = "sampleMenu" href = "#" title = "サンプル2" >サンプル2</ a > < ul class = "childMenu" > < li >< a href = "#" title = "Menu1" >Menu1</ a ></ li > < li >< a href = "#" title = "Menu2" >Menu2</ a ></ li > < li >< a href = "#" title = "Menu3" >Menu3</ a ></ li > < li >< a href = "#" title = "Menu4" >Menu4</ a ></ li > </ ul > </ li > < li >< a href = "#" title = "サンプル3" >サンプル3</ a ></ li > </ ul > |
説明続く。(結構長いです)
XHTMLを書いたら適当にスタイリングをしましょう。
ドロップダウンメニューになるリストを表示された時の位置に絶対指定で配置して、display:noneで非表示にしておきます。
ブラウザーの表示誤差を吸収するのを忘れずに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | a { text-decoration : none ; } ul { margin : 0 ; padding : 0 ; } ul#navigation { position : relative ; float : left ; } ul#navigation li { float : left ; list-style : none ; width : 100px ; text-align : center ; } ul#navigation a { display : block ; height : 30px ; background-color : #333 ; color : #fff ; line-height : 30px ; text-align : center ; } ul#navigation a:hover { background-color : #666 ; } ul#navigation ul.childMenu { position : absolute ; width : 100px ; top : 30px ; left : 100px ; } ul#navigation ul.childMenu li { float : none ; } ul#navigation ul.childMenu a { display : block ; background-color : #128E2D ; color : #fff ; } ul#navigation ul.childMenu a:hover { background-color : #66CC33 ; } .childMenu { display : none ; } |
FirefoxとIEはz-indexの解釈が違うので、z-indexの指定が非常に重要です。
どのように違うのかは参考のリンク先を見てみてください。
参考» 調べものブログ:IEとFirefoxでz-indexの扱いが異なる
javascript
改変出来るように順を追って説明します。
まずはボタンになるa要素とドロップダウンさせるリスト要素を取得します。
サンプルのソースではリストはボタンの次にある要素なので、getNext()で得られます。
1 2 3 4 | window.addEvent( 'domready' , function (){ var parentMenu = $( "sampleMenu" ); var childMenu = parentMenu.getNext( ".childMenu" ); }); |
ドロップダウンメニューの動きを大きく分けると3つになります。
- ボタンにマウスが乗ったらサブメニューを表示
- ボタンとサブメニューからマウスが離れたらサブメニューを隠す
- サブメニューにマウス乗ってる間はずっと表示
「乗ってる間」はoverと同じなので、使うイベントハンドラは「乗ったとき」の”mouseover”と「離れた時」の”mouseleave”になります。
“mouseout”じゃない理由はソース書き変えて実際に動作を見てみてください。
要素へのイベントの追加はaddEventメソッドで行えますが、今回は2つ同時に追加しなくてはならないのでaddEvents()を使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | parentMenu.addEvents({ "mouseover" : function (){ childMenu.setStyle( "display" , "block" ); }, "mouseleave" : function (){ childMenu.setStyle( "display" , "none" ); } }); childMenu.addEvents({ "mouseover" : function (){ this .setStyle( "display" , "block" ); }, "mouseleave" : function (){ this .setStyle( "display" , "none" ); } }); |
マウスオーバー時にスタイルを変更して隠してたリストを表示。マウスが離れたら逆に隠します。
childMenuの方のイベントは自身が対象なので、関数内では”this”を使います。
ここまで書けばドロップダウンっぽい動きはしますが、気になる点が幾つか…
- タイトルがいちいち表示されてうざい
- 消えるのが早すぎる
とりあえず上記2点を簡単に解決しときます。
まずタイトルですが、これは属性なのでremoveProperty()を使用します。
1 2 3 4 5 6 7 | var parentMenu = $( "sampleMenu" ); var childMenu = parentMenu.getNext( ".childMenu" ); //タイトル消す parentMenu.removeProperty( "title" ); childMenu.getChildren().each( function (li){ li.getElement( "a" ).removeProperty( "title" ); }); |
ドロップダウンさせるメニューの方はli要素を取得してからeach()で1つずつ処理します。
次に、遅延用の変数を追加。場所はどこでもいいです。
1 | var timer = null ; |
この変数はdelayによる遅延をキャンセルする際に使います。
上で書いたドロップダウンメニューのaddEvents()を変更します。
display:noneを関数にしてdelayを適用し、返り値が変数timerに入るようにします。
わざわざ関数にするのはdelayが関数にしか使えないからです。
1 2 3 4 5 6 7 8 9 10 | childMenu.addEvents({ "mouseover" : function (){ this .setStyles({ "display" : "block" }); if (timer){$clear(timer);} }, "mouseleave" : function (){ fnc = function (){ this .setStyle( "display" , "none" );} timer = fnc.delay(1000, this ); } }); |
mouseoverには「timerに何か入ってたら$clear()する」というソースを追加しました。
$clear()はdilay()などのタイマーを止める関数です。
同じようにボタンのイベントにも$clear()を追加します。
1 2 3 4 5 6 7 8 9 | parentMenu.addEvents({ "mouseover" : function (){ childMenu.setStyle( "display" , "block" ); if (timer){$clear(timer);} }, "mouseleave" : function (){ childMenu.setStyle( "display" , "none" ); } }); |
これでちょっとドロップダウンメニューらしさが増しました!(゚∀゚)
この程度ならフレームワーク使わなくても簡単に書けるレベルですが、
Fx.Tweenでスライドさせたり、fade()でフェードイン・アウトさせたりとちょっとしたエフェクトをつけても面白いです。(その分ソースはややこしくなりますが)
タブを使った場合にも対応させるなら’focus’と’blur’、キー動作に対応させるなら’keydown’を追加します。
こんにちは!最近サイトを作ってみました。
メニューがたくさんあるのでドロップダウンメニューにしたいなぁと思っています。
詳しく説明してあってとってもわかりやすくってありがたいです☆
私のサイトですが、メニューが縦に積み重なってるんです。
しかも、ドロップボックス(?)はなく、単純にテキストを書いてある所にリンクを張っただけなんですが、
それでも、ドロップダウンメニューをドロップして右、そのあと下にだすことって可能なんでしょうか???
こんなイメージです。
1
2
3
1にマウスをおくと、1からa.b.cが出てくる、という感じにしたいです。
1——a
2 -b
3 -c
これは縦に積み重なっているので複雑なんでしょうか??
waka さん >
この記事で作るドロップダウンメニューは、記事冒頭にある画像のように
CSSでメニューを作って完成状態にしてから
JavaScriptでdisplayプロパティを変更して表示非表示を切り替える。というものです。
なのでCSSで希望する位置にメニューを配置すれば縦型も作れます。
記事にあるサンプルソースだと30行目にあるセレクターで子メニューの位置を指定しています。
position:absolute で絶対位置指定にし、topとleftで.childMenuの表示位置を決定するものです。
top → メニューの高さと同じ=下に出る left → 親ボタンの位置と同じ
このとき、childMenu は左上の基準点を position:relative が指定してある ul#navigation と同じにするのですが、
縦並びだと各ボタンによって縦の位置が変わるので、ul#navigation の position:relative を ul#navigation li へ移動し
top:0; left:100px(メニューの幅と同じ) とすれば縦型に配置出来ると思います。
なお、floatはすべて削除してください。
こんにちは!
wakaです。
詳しくおしえていただいて、ありがとうございます!!!
さっそくやってみます!(できるかなぁ・・・・。)
がんばりまーーーーす!
waka@
こんにちは。
さっそくやってみました。
floatの部分は削除しましたが、
float:none;こちらも削除しました。
topもleftも教えてもらった通りに指定したんですが、
もしかして、表示するための箱のwidthが100pxでは大きすぎて表示されないのかなぁと思い、
10pxにしてみましたが、ピクリともしません(涙)
ul#navigation ul.childMenu {
position:absolute;
width:100px;
top:0px;
left:100px;
もうちょっといじってみます。
わか@
何度もすみません。
>縦並びだと各ボタンによって縦の位置が変わるので、ul#navigation の position:relative を ul#navigation li へ移動し
この移動っていうのはどういうことですか??
初歩的なことでお恥ずかしいですが、おしえてください。
おねがいします。
わか@
いろいろ勉強させていただきました!ありがとうございました♪