CSS(+JS)でULのドロップダウンメニュー

以前のエントリーで書いた物と考え方は同じですが、一般的にメニューリストとして使われるUL+ノードを辿ってイベントハンドラを後付けするサンプルです。IE6,IE7,Mac IE5.2, Firefox2.0, Opera8, Opera9, Safari2で動作する事を確認しています。
IE5.0,IE5.5でも多分大丈夫だと思いますが、CSSの解釈がアレゲなのでソレゲが生えてるかも。

Example

CSS

例えば、#navi lifloat:left;を消し、#navi li.plist:hover ulmargin-left:50px;margin-top:-25px;を追加する事で簡単に垂直のレイアウトに変更出来ます。
縦置きがどんな感じかはサンプルメニューのSTYLEからV MENUをクリックしてみて下さい。 但しIEで動作させると、横幅指定の関係で回り込みが効かず、この文章があるブロック要素が落ちてしまいます。


#toc_container{
  width: 510px;
  background-color:#fff;
  color:#000;
}
#toc_container ul,#toc_container li{
  list-style:none;
  margin:0;
  padding:0;
}

  #root_toc li,
  #root_toc li a
  {
    width: 100px;
  }
  
  #root_toc li{
    float:left; /* 縦にする場合はこの指定は不要 */
    border:1px solid #ccc;
  }

  #root_toc li.plist ul{
    display:none;
    position:absolute;
  }
  #root_toc li.plist:hover  > a
  {
    background-color:#f60;
  }
  #root_toc li.plist:hover ul{
    display: block;
    /* 縦にする場合は次の指定を使う
    margin-left:90px;
    margin-top:-25px;
    */
  }
    #root_toc li.plist li{
      float:none;
      display:list-item;
    }
  #root_toc li a{
    display: block;
    /*boxの扱いの差が出るのでpaddingは使わない*/
    text-indent:0.3em;
    line-height:1.8em;
    color:#fff;
    background-color: #666;
    text-decoration:none;
  }
  #root_toc li a:hover
  {
    color:#000;
    background-color:#fff;
  }

HTML

ドロップダウンさせるLI要素にクラスplistを指定します。

リスト系の要素を使った場合、キャリッジリターンやホワイトスペースでリスト項目の上下に隙間が出来るブラウザがあります。
この場合、LI要素の中の要素、例えばA要素の閉じタグの直前で改行を入れる事で解消できる事が多いようです。

以前のエントリーで教えてもらったのですが、Flashムービーにメニューが被る場合はムービーのObject要素に<param name="wmode" value="transparent">、embed要素の属性値にwmode="opaque"を設定します。
サンプルメニューのSTYLE→SWFをクリックしてみて下さい。サンプルメニューの下にFlashムービーを表示します。
それでもSafariだけはメニューがチラついてしまいます…


<div id="toc_container">
  <ul id="root_toc">
    <li class="plist"><a href="#">↓Foo
    </a>
      <ul>
        <li><a href="#">Foo 1
        </a></li>
        <li><a href="#">Foo 2
        </a></li>
        <li><a href="#">Foo 3
        </a></li>
      </ul>
    </li>
    <li class="plist"><a href="#">↓Bar
    </a>
      <ul>
        <li><a href="#">Bar 1
        </a></li>
        <li><a href="#">Bar 2
        </a></li>
        <li><a href="#">Bar 3
        </a></li>
        <li><a href="#">Bar 4
        </a></li>
        <li><a href="#">Bar 5
        </a></li>
      </ul></li>
    <li><a href="#">Baz</a></li>  
    <li class="plist"><a href="#">↓Quux
    </a>
      <ul>
        <li><a href="#">Quux 1
        </a></li>
        <li><a href="#">Quux 2
        </a></li>
        <li><a href="#">Quux 3
        </a></li>
        <li><a href="#">Quux 4
        </a></li>
      </ul></li>
  </ul>
</div>

Javascript

IE専用のスクリプトです。
要素やCSSに手を加えた場合、root_tocplistULを適宜変更すれば…多分…動きます。
jsの扱いは以前のエントリーと同じです。


//window.onload = function(){//<head>にスクリプトを配置する場合は行先頭のコメントアウトを外す
if(document.getElementById && document.all && !navigator.userAgent.match(/Opera/)){
  var obj = document.getElementById("root_toc");
  for(var i=0;i<obj.childNodes.length;i++)
  {
    if(obj.childNodes[i].className=="plist")
    {
      obj.childNodes[i].onmouseover = function(){pull(this)};
      obj.childNodes[i].onmouseout = function(){pull(this)};
    }
  }
}
//}//<head>にスクリプトを配置する場合は行先頭のコメントアウトを外す

function pull(obj){
  for(var i=0;i<obj.childNodes.length;i++)
    if(obj.childNodes[i].nodeName.toUpperCase()=="UL")
      obj.childNodes[i].style.display=obj.childNodes[i].style.display=="block"?"none":"block";
}

だそく

ドロップダウンメニューは全ての項目を一瞥出来ないのが問題だと思うのですが、ブログの月別リンクのようにダラダラ長くなる割に、リンクのテキストからリンク先の内容を推測出来ないようなメニューは畳んでしまう方が良いかも知れませんね。

以前のエントリーfor文などでノードを辿って属性設定するよりコッチのほうが処理速度も早いようです云々書いてましたが、ブラウザによってDOMも正規表現も処理速度に差があり、一概には言えないようです。iTunes Music Library.xmlをDOM or 正規表現でHTMLに整形出力するスクリプトで時間を計って確認してみたのですが、例えばFirefoxは若干DOMの方が早く、同じMozillaでもCaminoは若干正規表現の方が良い結果が出ました。
ちなみに一番早かったのがブッチギリでSafariの正規表現。馬鹿みたいに早いです。
その分DOMの処理はブラウザがフリーズしたのかと思うぐらい遅いのですが…


コメント
管理人様

こんにちは、nadaです。

ulドロップダウンメニューを記事にしていただいてありがとうございます。

早速cssはそのままで、こちらのjsに差し替えたところ、IEでもドロップダウンメニューが動作しました!

動作確認したのは以下のブラウザです。

win IE5〜 FF1.5.0.8 opera9
mac IE5.2 safari2.0.4 FF1.5.0.8

js勉強しなくちゃなあと思いつつ、ずっと見て見ぬふりをしていましたが、今回の件でもっとちゃんと勉強しようと思えました。
よいソースを教えていただいてありがとうございました。

また寄らせていただきますね。
  • nada
  • 2006/12/15 1:02 PM
nadaさん、こんにちは。
解決されたのですね。お疲れ様でした。
Javascriptは始めるのが手軽なので楽しんで下さい。覚えればActionScriptにも応用が利くし、他のスクリプト言語も覚え易くなると思いますよ。
…と、言っても私も分からない事だらけです…(--;
  • Faro管理人
  • 2006/12/16 8:12 PM
管理人様

こんにちは。先日ドロップダウンメニューの件でお問い合せさせていただきましたhanaです。
先日の件はクリアしたのですが、どうしてもulで制作しなくてはならない事になり再びご迷惑と思いながらも投稿させていただきました。

制作は順調に進んでいたのですが、どうしてもwindows ie6にてプルダウンメニューが表示されません。試しに管理人様のソースをそのまま当サーバへ設定してみたのですが、それでも無理でした。
(ちなみにこちらのブログにあるメニューは正常に動作しております。)
八方塞がりとなってしまい、大変申し訳ないのですが、下記のアドレスをご覧いただけませんでしょうか?

http://www.geo-labo.com/d_menu/index03.html

もし、お知恵をお借りできれば幸いです。
  • hana
  • 2006/12/21 5:56 PM
すみません。
どうやら何かいらぬソースが入っていたようで、こちらで解決することができました。
ご面倒をお掛けして本当に申し訳ございませんでした。

今後ともよろしくお願いいたします。
取り急ぎお礼までで失礼します。
  • hana
  • 2006/12/22 4:21 PM
見る前に解決されたようですね。お疲れ様でした。
私も小さい事で嵌りがちなので分かります。どうぞお気になさらず。
…解決した時の脱力感は割と好きですが^^;
  • Faro管理人
  • 2006/12/22 7:55 PM
Faro管理人様、はじめまして。ulドロップダウンメニューの作成方法、参考にさせていただいています。Javascriptは全くわからないし、CSSはやっと使い方がわかってきたかなという初心者ですので、親切丁寧に記述されているのは大変助かります。

私が現在作成しているページでは、常に表示されているメニューに、それぞれ幅のサイズが異なる画像を使用しています。そのまま利用させていただくと、ドロップダウン部分が次のメニューの下に表示されてしまいました。それ自体はposition:absolute;を指定して直すことができたのですが、それぞれの画像の幅が違う為に
#root_toc li,
#root_toc li a {
width: 100px;
}
を指定できません。ドロップダウン部分が不安定になっていたので原因を探していた所、この指定がないためではないかという結果になりました。リンク部分を安定表示できないなら使わないほうがいいし、とジレンマに陥っています。
もし、何かいいアイディアをお持ちでしたら、ぜひお聞かせいただきたいと思い、コメントを書かせていただきました。
よろしくお願いします。
  • Chuki
  • 2007/04/16 12:24 AM
Chukiさん、こんにちは。はじめまして。
色々不明な点が多いのですが、それぞれの画像の幅に合わせて個別にサイズ指定を行った場合は問題無く使えるのでしょうか?
  • Faro管理人
  • 2007/04/16 8:02 PM
Faro管理人さま、早速のご返事ありがとうございます。
長くて申し訳ありませんが、ソースを貼り付けてみました。ご指摘のように、画像ごとに幅の指定を行うと、リンクは安定しました(一つのliに二つの指定が出来ることを知りませんでした)。またこの指定のおかげで、ドロップダウン部分の表示の為につけていた(position:absolute;..)の指定が不要になりました。

現在一つ問題点があり、ドロップダウン枠線の幅いっぱいにリンクを認識してくれません。display: block;の扱い方が悪いのではないかと思っておりますが、いかがでしょうか?
お忙しいなか申し訳ありませんが、よろしくお願いします。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML lang="en-AU">
<HEAD>
<TITLE>Title</TITLE>
<META http-equiv="content-type" content="text/html; charset=iso-8859-1">
<SCRIPT language=javascript src="warregotameshi.js" type=text/javascript></SCRIPT>
<STYLE TYPE="text/css">
body{
color: #000;
text-align: left;
background-color: #fff;
background-image: url(#);
margin: 0px;
}
a:link {
color: #0000ff;
text-decoration: underline;
}
a:visited {
color: #000080;
text-decoration: underline;
}
a:active {
color:#ff0000;
text-decoration: none;
}
a:hover {
color: #ff0000;
text-decoration: none;
position: relative;
}
#container{
margin: 0px 0px 0px 50px;
width: 700px;
text-align: left;
border: 1px solid #000;
}
#logo{
margin: 0px;
position: absolute; left:51px; top:0px;
}
#toc_container {
position: absolute; left:51px; top:130px;
width: 700px;
background: #000
}
#toc_container img {
border: 0px;
}
#toc_container ul,#toc_container li{
list-style:none;
margin:0;
padding:0;
}
#root_toc li {
float:left;
}
#root_toc li.plist ul{
display:none;
position:absolute;
width: 150px;
font-size: 90%;
}
#root_toc li.plist:hover ul{
display: block;
}
#root_toc li.plist li{
float:none;
display:list-item;
border-width: 0px 1px 1px 1px;
border-style: solid;
border-color: #8B0021;
padding: 3px 5px;
background: #ffcccc
}
#root_toc li a{
display: block;
width: 150px;
}
#menu01 {
width: 55px;
}
#menu02 {
width: 105px;
}
#menu03 {
width: 110px;
}
#menu04 {
width: 65px;
}
#menu05 {
width: 50px;
}
#menu06 {
width: 150px;
}
#menu07 {
width: 75px;
}
#menu08 {
width: 90px;
}
</STYLE>
</HEAD>
<BODY>
<div id="container">
<div id="logo">
<img src="#" width=700 height=130 border=0>
</div>
<div id="toc_container">
<ul id="root_toc">
<li id="menu01"><a href="#"><img src="01.jpg" width=55 height=20>
</a></li>
<li id="menu02"><a href="#"><img src="02.jpg" width=105 height=20>
</a></li>
<li class="plist" id="menu03"><a href="#"><img src="03.jpg" width=110 height=20>
</a>
<ul>
<li><a href="#">LINK031</a></li>
<li><a href="#">LINK032</a></li>
<li><a href="#">LINK033</a></li>
<li><a href="#">LINK034</a></li>
<li><a href="#">LINK035</a></li>
<li><a href="#">LINK036</a></li>
</ul></li>
<li class="plist" id="menu04"><a href="#"><img src="04.jpg" width=65 height=20>
</a>
<ul>
<li><a href="#">LINK041</a></li>
<li><a href="#">LINK042</a></li>
<li><a href="#">LINK043</a></li>
<li><a href="#">LINK044</a></li>
<li><a href="#">LINK045</a></li>
</ul></li>
<li class="plist" id="menu05"><a href="#"><img src="05.jpg" width=50 height=20>
</a>
<ul>
<li><a href="#">LINK051</a></li>
<li><a href="#">LINK052</a></li>
<li><a href="#">LINK053</a></li>
<li><a href="#">LINK054</a></li>
</ul></li>
<li id="menu06"><a href="061function.html"><img src="06.jpg" width=150 height=20></a></li>
<li class="plist" id="menu07"><a href="#"><img src="07.jpg" width=75 height=20>
</a>
<ul>
<li><a href="#">LINK061</a></li>
<li><a href="#">LINK062</a></li>
<li><a href="#">LINK063</a></li>
<li><a href="#">LINK064</a></li>
</ul></li>
<li id="menu08"><a href="#"><img src="08.jpg" width=90 height=20>
</a></li>
</ul>
</div></div>
</BODY>
</HTML>
  • Chuki
  • 2007/04/16 10:58 PM
Faro管理人さま、たびたびお邪魔します。
今までIE7でのみの動作確認をしていましたが、FirefoxとOperaをインストールして確認すると、上記のスクリプトでは何も見えないことがわかりました。失礼しました。

ここに記載する為に上記のように変更する前の元のスクリプトでは、希望通りの動きをしました(Macは持っていないため確認できません。本当は一台欲しいのですが…)。
ということは、IEのみの問題ということでしょうか?

どうも出直してきたほうが良さそうな感じですね。一つ上のコメント、長文ですので削除していただいて構いません。
もう一度色々試してみて、駄目そうでしたら再度質問させていただくかも知れません。ありがとうございました。
  • Chuki
  • 2007/04/18 10:04 PM
Chukiさん、こんばんは。
私の方で確認した限り、Javascript無しでFirefoxとSafariは正常に使えました。

IE7の問題かも知れませんね。
一応他のモダンブラウザのように
*:hover {}
*:hover *{}
に対応したようですが、メニュー全体を格納した要素にポジショニング指定した場合、挙動が怪しくなるようです。
jSの処理をタイマー関数で遅延させる等で上手くいくかもしれません。
私も気になるので上手い解決方法を探してみます。
  • Faro管理人
  • 2007/04/19 12:36 AM
管理人様

はじめまして。schocolaholicと申します。
CSSもJSも未熟者ですが、なんとかシンプルな記述でのドロップダウンメニューを実現したくて、こちらにたどり着きました。
大変参考になる明確な記述と解説だったので、CSSで希望通りの動作を実現することができました。ありがとうございました。

ただひとつうまくいかないことがあるので、もしよろしければアドバイスをいただけたらと思います。。。

私もChukiさんと同じく、常に表示されているメニューには画像を使用したいと思っています。
画像は固定でなくロールオーバーで、hoverの間は違う画像に入れ替わるようにしたいので
常に表示されているliにidを指定し

#m_home a:link,
#m_home a:hover{
background: transparent url(img/menu/m_home.gif) left top no-repeat;
width: 90px;
height: 40px;
text-indent:-9999px;
}
#m_home a:hover{
background-position:0 -40px;
}

このような記述を加えました。

ただこれだけだと、下にドロップダウンが出ないリスト(管理人様の例だと <li><a href="#">Baz</a></li> の部分)は希望通りロールオーバーできるのですが、下にドロップダウンが出るリストだと、ドロップダウンメニュー部分にもこのidの指定が適用されてしまいます。

ドロップダウン部分にはこのidの指定を適用せず、plistのclass指定のみを適用し、作成例のようにテキストのみを表示するようにはできるでしょうか。

ご面倒なことをお願いしてしまい申し訳ございません。。
  • schocolaholic
  • 2007/04/26 11:36 PM
schocolaholicさん、こんちには。はじめまして。

”#m_home a”の場合、li要素に含まれるa要素全てに適用されてしまうので、a要素に直接IDを付けるのが良いかも知れません。

CSSです。
#toc_container a#m_home:link,
#toc_container a#m_home:hover{
background: transparent url(画像) left top no-repeat !important;
text-indent:-9999px;
width: 90px;
height: 40px;
}
#toc_container a#m_home:hover{
background-position:0 -40px !important;
}

#toc_containerと!importantは必要無いかもしれません。
そしてHTMLです。
<li class="plist"><a href="#" id="m_home">↓Foo

未検証なのでIEでおかしな挙動になるかもしれません。

比較的新しいブラウザだけを対象にするなら
#toc_container #m_home > a:link,
#toc_container #m_home > a:hover
という記述でも処理可能だと思います。
IE7も確か「>」は使えるようになったと思うのですが…ちょっと自信が無いです。ごめんなさい。
  • Faro管理人
  • 2007/04/28 3:40 PM
管理人様

お返事ありがとうございました。
aにidをつけるという発想がまったくなかったので感動してしまいました。。
ご丁寧にソースも記述していただいて、助かりました。

教えていただいた記述で、FireFoxでは動作確認できたのですが、やはりIEは難しいようです。
IE7もまだメジャーではありませんし、やはり画像置換部分はJSで制御するか、使用しないほうがいいのかもしれません。

設置について、もう少し検討してみます。
ありがとうございました。
  • schocolaholic
  • 2007/04/29 12:42 PM
schocolaholicさん、こんにちは。
確認がすっかり遅くなりました。もう見ていないかな…すいません。

あー…IE駄目でしたか。お役に立たなかったようで残念です。
上の方法だとID指定のあるA要素にマウスカーソルが重なっている間しか変わらないので、ドロップダウンしている間は常に画像が変わり続ける必要があるならCSSだけでは恐らく無理で、schocolaholicさんのお考え通りにjsで制御した方が良さそうですね。
ちょっとやっつけですが参考程度に見て下さい。
//CSS
#toc_container a#m_home{
background: url(image003.jpg) 0 0 no-repeat;
text-indent:-9999px;
width: 90px;
height: 40px;
}
#toc_container a#m_home:hover{
background-position:0 -40px;
}
//JS
function pull(obj){
for(var i=0;i<obj.childNodes.length;i++){
if(obj.childNodes[i].nodeName.toUpperCase()=="UL"){
var css =obj.childNodes[i].style.display=="block"?"none":"block";
obj.firstChild.style.backgroundPosition = css=="block"?"0 -40px":"0 0";
obj.childNodes[i].style.display = css;
}
}
}

  • Faro管理人
  • 2007/05/03 11:57 PM
管理人様

たびたびお返事ありがとうございます。
見にきてよかったです(笑)

CSSのみの背景画像置換だとやはりユーザビリティ云々(画像OFFの場合に不便)という方もおられますし・・・
現実にはJSも使用しつつというのが無難なのですよね。
ドロップダウンがCSSでできることを教えていただいただけでも、かなり勉強になりました。
JSはまだまだ勉強不足なのですが、上記の記載を参考にして、もう一度挑戦してみようと思います。
本当にありがとうございます。
  • schocolaholic
  • 2007/05/05 11:29 PM
schocolaholicさん、こんにちは。
>ユーザビリティ
うーん、そうですね。完全にCSS無効なら問題無いのですが…画像だけ無効の人には何がなんだか分からなくなりますね。
あー、CSS無効もメニューが全部展開してしまいますダメだー(^^;
画像のロードイベントもあまり当てにならないし、どこかで妥協するしかなさそうですね。
新しい発見などありましたら是非教えてください。
  • Faro管理人
  • 2007/05/07 10:28 PM
管理人様

はじめまして。cherryboyと申します。

ドロップダウンメニューを愛用させていただいております。

私、CSSもJSも未熟者なのでどうしても分からない事が1点ありますので、教えていただければと思います。

以下のページ
http://www.handyman.jp/menu.htm
でテストをしているのですが、IE6だとどうしても正常に表示されません。
いろいろと試してみたのですが、CSSとJSの知識が浅い為八方ふさがりになってしまいました。
CSSとJSに問題があるかと思うのですが、どうすれば良いかおしえていただけますでしょうか?

宜しくお願い致します。
  • cherryboy
  • 2008/02/15 1:01 PM
cherryboyさん、はじめまして。こんにちは。

IE6で検証出来る環境が無いので何とも言えないのですが、このページで使用しているソースコードはサンプル用に余計な処理が含まれています。
試しに記事中のサンプルコードを使用してみて下さい。
縦のレイアウトにする場合はCSSのコメントで指定している箇所の変更を行ってください。
  • Faro管理人
  • 2008/02/16 4:03 PM
はじめまして

ドロップダウンメニューを探していてたどり着きました。

他の方の質問にあったのと同じなのかもしれませんが、IE6での挙動が怪しいのです。

最初に読み込んだときには動かず、他のページに移動してから戻ってくると正しく動きます。

jqueryのような他のライブラリなどと組み合わせると、干渉して上手く動かなくなってしまうケースなどありますか?

恐れ入りますがお手すきなときにでもアドバイスいただけたら嬉しいです。
  • kagome
  • 2008/02/20 11:31 PM
kagomeさん、こんちには。はじめまして。

>最初に読み込んだときには動かず、他のページに移動してから戻ってくると正しく動きます。
うわ、なんだろ。環境作って調べてみます…すいません頼りなさすぎです^^;
ライブラリとの干渉についてですが、jQueryと変数や関数名がかぶっていると挙動に影響が出るかもしれません。
関数化してライブラリのイベント処理で呼び出すように変更してみて下さい。
実際に使った訳ではないのですが、jQueryの場合、$(document).ready(func)か$(func)という形でロード時に処理出来るそうです。
ループ処理などもライブラリを使って小さくする事が出来ると思いますのでお試し下さい。
  • Faro管理人
  • 2008/03/12 7:19 PM
こんにちは、初めまして秀といいます。
初めてドロップダウンメニューを作るのですがJavascriptの部分は何所に入れたらいいのでしょうか?HTMLのどこかにいれるのですか?それともJavascriptの外部ファイルをつくのですか?
  • 2008/03/13 11:30 PM
秀さん、こんにちは。すいません、お返事が遅くなりました。
ちゃんと管理しないと駄目なのですが中々…申し訳ないです。

スクリプトをメニューより後であれば外部でも直接記述しても大丈夫です。
メニューより前、例えば<head>〜</head>に入れて記述したり、外部から読み込む場合は
「行先頭のコメントアウトを外す」と書かれた行の先頭にある「//」を消して下さい。
  • Faro管理人
  • 2008/04/01 7:36 PM
コメントする








   
この記事のトラックバックURL
トラックバック

selected entries

categories

archives

recent comment

recent trackback

links

profile

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM