メガドロップダウンメニューをjQueryとCSSで作る:via Mega Drop Down Menus w/ CSS & jQuery

サイトが巨大化するにつれ、多くの情報を一度に見せられる方法が運営者に求められています。
それを解決する一つの手段がメガドロップダウンメニューです。
一見、ユーザビリティ上好ましく見えないかもしれませんが、ユーザビリティの第一人者「Jakob Nielsen」はAlertbox: メガドロップダウン式のナビゲーションメニューは効果あり(2009年03月23日)と述べています。
今回はjQueryを利用して、メガドロップダウンメニューを作成してみたいと思います。
via:Mega Drop Down Menus w/ CSS & jQuery

sponsors

使用方法

※長いので、先にサンプルを見る
まず以下のようなメニューが記述されているとします。

<ul id="topnav">
    <li><a href="#" class="home">Home</a></li>
    <li><a href="#" class="products">Products</a></li>
    <li><a href="#" class="sale">Sale</a></li>
    <li><a href="#" class="community">Community</a></li>
    <li><a href="#" class="store">Store Locator</a></li>
</ul>
またCSSは下記のようにCSS Spriteにより書かれています。

ul#topnav {
	margin: 0; padding: 0;
	float:left;
	width: 100%;
	list-style: none;
	font-size: 1.1em;
}
ul#topnav li {
	float: left;
	margin: 0; padding: 0;
	position: relative; /*--ここ大事--*/
}
ul#topnav li a {
	float: left;
	text-indent: -9999px;
	height: 44px;
}
ul#topnav li:hover a, ul#topnav li a:hover { background-position: left bottom; } 
ul#topnav a.home {
	background: url(nav_home.png) no-repeat;
	width: 78px;
}
ul#topnav a.products {
	background: url(nav_products.png) no-repeat;
	width: 117px;
}
ul#topnav a.sale {
	background: url(nav_sale.png) no-repeat;
	width: 124px;
}
ul#topnav a.community {
	background: url(nav_community.png) no-repeat;
	width: 124px;
}
ul#topnav a.store {
	background: url(nav_store.png) no-repeat;
	width: 141px;
}
これにドロップダウンさせるメニューを書きます。

    <li>
    	<a href="#" class="products">Products</a>
        <-- こっから追加 -->
        <div class="sub">
            <ul>
                <li><h2><a href="#">Desktop</a></h2></li>
                <li><a href="#">Navigation Link</a></li>
                <li><a href="#">Navigation Link</a></li>
            </ul>
            <ul>
                <li><h2><a href="#">Laptop</a></h2></li>
                <li><a href="#">Navigation Link</a></li>
                <li><a href="#">Navigation Link</a></li>
            </ul>
            <ul>
                <li><h2><a href="#">Accessories</a></h2></li>
                <li><a href="#">Navigation Link</a></li>
                <li><a href="#">Navigation Link</a></li>
            </ul>
            <ul>
                <li><h2><a href="#">Accessories</a></h2></li>
                <li><a href="#">Navigation Link</a></li>
                <li><a href="#">Navigation Link</a></li>
            </ul>
        </div>
        <-- ここまで追加 -->
    </li>
追加したメニューのCSSを調整します。

ul#topnav li .sub {
	position: absolute; /*--ここ大事--*/
	top: 44px; left: 0;
	background: #344c00 url(sub_bg.png) repeat-x; 
	padding: 20px 20px 20px;
	float: left;
	/*--Bottom right rounded corner--*/
	-moz-border-radius-bottomright: 5px;
	-khtml-border-radius-bottomright: 5px;
	-webkit-border-bottom-right-radius: 5px;
	/*--Bottom left rounded corner--*/
	-moz-border-radius-bottomleft: 5px;
	-khtml-border-radius-bottomleft: 5px;
	-webkit-border-bottom-left-radius: 5px;
	display: none; /*--JSオフ時に表示されないようにします--*/
}
ul#topnav li .row { 
	clear: both;
	float: left;
	width: 100%;
	margin-bottom: 10px;
}
ul#topnav li .sub ul{
	list-style: none;
	margin: 0; padding: 0;
	width: 150px;
	float: left;
}
ul#topnav .sub ul li {
	width: 100%;
	color: #fff;
}
ul#topnav .sub ul li h2 { 
	padding: 0;  margin: 0;
	font-size: 1.3em;
	font-weight: normal;
}
ul#topnav .sub ul li h2 a { 
	padding: 5px 0;
	background-image: none;
	color: #e8e000;
}
ul#topnav .sub ul li a {
	float: none;
	text-indent: 0; /*--text-indent戻します--*/
	height: auto; 
	background: url(navlist_arrow.png) no-repeat 5px 12px;
	padding: 7px 5px 7px 15px;
	display: block;
	text-decoration: none;
	color: #fff;
}
ul#topnav .sub ul li a:hover {
	color: #ddd;
	background-position: 5px 12px ;
}
最後にJavaScriptを書いていきます。
必要なのはjQueryのjquery.jsとプラグインhoverIntent jQuery Plug-inになります。

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.hoverIntent.js"></script>
<script type="text/javascript">
$(document).ready(function(){
//マウスオーバー時
function megaHoverOver(){
   	 $(this).find(".sub").stop().fadeTo('fast', 1).show(); 
    (function($) {
        jQuery.fn.calcSubWidth = function() {
            rowWidth = 0;
            $(this).find("ul").each(function() { 
                rowWidth  = $(this).width(); 
            });
        };
    })(jQuery); 

    if ( $(this).find(".row").length > 0 ) {

        var biggestRow = 0;	

        $(this).find(".row").each(function() {
            $(this).calcSubWidth();
            //Find biggest row
            if(rowWidth > biggestRow) {
                biggestRow = rowWidth;
            }
        });

        $(this).find(".sub").css({'width' :biggestRow});
        $(this).find(".row:last").css({'margin':'0'});

    } else { 

        $(this).calcSubWidth(); 
        $(this).find(".sub").css({'width' : rowWidth});

    }
}
//On Hover Out
function megaHoverOut(){
  $(this).find(".sub").stop().fadeTo('fast', 0, function() {
      $(this).hide();  //after fading, hide it
  });
}

var config = {
     sensitivity: 2,
     interval: 100,
     over: megaHoverOver,
     timeout: 500, 
     out: megaHoverOut 
};

$("ul#topnav li .sub").css({'opacity':'0'}); 
$("ul#topnav li").hoverIntent(config); 

});
</script>
上記のロジックは以下の通りとなります。
▼マウスオーバー時
  1. ドロップダウンさせる.subをフェードイン
  2. .rowの存在を確認 (複数行を使用する場合)
  3. .rowがあれば,一番広い行の幅に全体をあわせる
  4. .rowがなければ.subの幅にあわせる
▼マウスアウト時
  1. ドロップダウンさせていた.subをフェードアウト
  2. .subを完全に隠す

サンプル

Javascriptサンプルページ一覧
skuare.net