jQueryで水平方向にスライドする開閉式メニュー

入れ子構造のリストでjQueryを使ったシンプルな開閉式メニューを自作してみたところ、CSSやjQueryで色々と不具合に遭遇しました。

CSSだとIEだけ表示が違ったりすることはよくありますが、jQueryでもブラウザー毎に挙動が違うことがあるようで久しぶりにハマりました…

HTML

まずは入れ子構造のHTMLを用意します。
※classを付ける箇所は自由に変更してもらって構いません。参考程度の構造になります。

<div class="SlideNav">
  <ul>
    <li class="Trigger"><a href="/hoge/">hoge</a>
      <ul>
        <li><a href="/hoge/01.html">hoge 01</a></li>
        <li><a href="/hoge/02.html">hoge 02</a></li>
        <li><a href="/hoge/03.html">hoge 03</a></li>
      </ul>
    </li>
    <li class="Trigger"><a href="/fuga/">fuga</a>
      <ul>
        <li><a href="/fuga/01.html">fuga 01</a></li>
        <li><a href="/fuga/02.html">fuga 02</a></li>
        <li><a href="/fuga/03.html">fuga 03</a></li>
        <li><a href="/fuga/04.html">fuga 04</a></li>
        <li><a href="/fuga/05.html">fuga 05</a></li>
      </ul>
    </li>
  </ul>
</div>

サンプルを見る

CSS

サンプルからの抜粋です。

.SlideNav ul {
  border-top: 1px solid #ccc;
}

.SlideNav a {
  display: block;
  position: relative;
  border: 1px solid #ccc;
  border-top: 0 none;
  width: 182px;
  line-height: 1.5;
  padding: 4px 8px;
  background-color: #eee;
  color: #333;
  text-decoration: none;
  /zoom: 1;
}

.Trigger {
  position: relative;
  /zoom: 1;
}

.Trigger ul {
  display: none;
  position: absolute;
  top: -1px;
  left: 199px;
}

IE6~8でa:hoverするとリストの下に余白ができる

.SlideNav {
  border-top: 1px solid #ccc;
}

.SlideNav ulに指定しているborder-topを親要素の.SlideNavに指定するとhover時に余白ができるのでulに指定します。一番目のリストをli.Firstとし、border-topを指定する方法などでもOKでしょう。

IE8でborderのレンダリングに不具合

.SlideNav a {
  line-height: 1.4;
}

line-heightを1.4以下に指定すると一部のborderが表示されない場合があるので1.5以上にします。
ちなみにheightを指定すれば解決しますが、拡張性がないので却下。
※他にも解決策があるかもしれません。

jQuery

ポイントはマウスが離れた時の処理(mouseleave)で入れ子のulが非表示になるように設定することです。サンプルではfadeOutを使用しました。
念のため、クリックした場合にも同じ処理を実装します。

$(function(){
  $('.Trigger').hover(function(){
    $(this).find('ul').stop(true, true).animate(
      {width: 'toggle', opacity: 'toggle'}
    );
  },function(){
    $(this).find('ul').fadeOut('fast');
  });
  
  $('.SlideNav a').click(function(){
    $('.Trigger ul').fadeOut('fast');
  });
});

※サンプルはjQuery 1.4.4を使用しています。

ブラウザーの「戻るボタン」を使用するとtoggleの動作に不具合

$(function(){
  $('.Trigger').hover(function(){
    $(this).find('ul').stop(true, true).animate(
      {width: 'toggle', opacity: 'toggle'}
    );
  });
});

当初、上記コードだけでも動作するかと思っていましたが、何度かページ遷移を繰り返すとFirefox、Safari、Chrome、Operaで不具合が生じます(IEでは不具合を確認できませんでした)。

  1. 展開したメニューからページ遷移
  2. ブラウザーの「戻るボタン」で前のページに戻る

不具合の内容

  • toggleのアニメーションが続く(メニューが開いたり閉じたりする)
  • メニューが開いたままになる

hoverするだけなら問題ないのと、毎回不具合が再現されるわけでもないようなので気付きませんでした。
単純に私のjQueryの書き方のせいですが…

検証ブラウザー
Firefox 3.6.13
Safari 5.0.3
Chrome 8.0.552.224
Opera 10.63
IE6~8

※バージョンナンバーはMac版のものです(IE以外)。Windowsでも同様の現象が見られました。