WEBOPIXEL

jQueryのサイドバー固定サブメニュー実装パターン

Posted: 2018.04.27 / Category: javascript / Tag: ,

最近はモニターのサイズがワイドなってきていることもありサイドバーを固定する機会が増えてきましたね。
そこでjQueryを使用したサイドバー固定にしたときのサブメニューの動きをいくつかご紹介します。

Sponsored Link

基本構造

navの子要素にulでマークアップします。
サブメニューはliの子要素のさらに子要素にulを入れ込みます。

HTML

<aside id="sidebar">
	<h1 id="brand-logo">Logo</h1>
	<nav id="global-nav">
		<ul>
			<li><a href="#">Home</a></li>
			<li class="sub-menu">
				<a href="#">About</a>
				<ul class="sub-menu-nav">
					<li><a href="#">About 1</a></li>
					<li><a href="#">About 2</a></li>
					<li><a href="#">About 3</a></li>
				</ul>
			</li>
			<li class="sub-menu">
				<a href="#">Products</a>
				<ul class="sub-menu-nav">
					<li><a href="#">Product 1</a></li>
					<li><a href="#">Product 2</a></li>
					<li><a href="#">Product 3</a></li>
					<li><a href="#">Product 4</a></li>
				</ul>
			</li>
			<li>
				<a href="#">Link</a>
				<ul class="sub-menu-nav">
					<li><a href="#">Link 1</a></li>
					<li><a href="#">Link 2</a></li>
					<li><a href="#">Link 3</a></li>
				</ul>
			</li>
			<li><a href="#">Contact</a></li>
		</ul>
	</nav>
</aside>

サイドバーはposition: fixedで固定になります。

CSS

#sidebar {
	font-size: 15px;
	padding: 30px 0;
	width: 260px;
	height: 100%;
	position: fixed;
	color: #033560;
	background: #fff;
	text-align: center;
}

アコーディオンの矢印マークは:after擬似要素で表示します。
is-activerotateを変更することアコーディオン開閉時の矢印の向きを制御します。
is-activeクラスを切り替えはJavaScriptで行います。

CSS

#global-nav .sub-menu > a:after {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	right: 18px;
	margin: auto;
	vertical-align: middle;
	width: 8px;
	height: 8px;
	border-top: 1px solid #033560;
	border-right: 1px solid #033560;
	transition: all .2s ease-out;
	transform: rotate(135deg);
}
#global-nav .sub-menu.is-active > a:after {
	transform: rotate(-45deg);
}

シンプルなアコーディオンタイプ

クリックするとサブメニューがアコーディオンが開く、一番オーソドックスなタイプです。

シンプルなアコーディオンタイプイメージ

アコーディオンはCSSでも頑張ればできますが、JSで書いた方がスマートですね。
jQueryのSlideでもいいですが、Velocity.jsというライブラリを使用することでスムーズにアニメーションできます。
is-activeクラスの切り替えは開いたときの矢印の切り替えに使っています。

JavaScript

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.0.0/velocity.min.js"></script>
<script type="text/javascript">
(function($) {
    $(function () {
        $('.sub-menu > a').on('click', function (e) {
            e.preventDefault();
            var $subNav = $(this).next('.sub-menu-nav');
            if ($subNav.css("display") === "none") {
                $(this).addClass('is-active');
                $subNav.velocity('slideDown', {duration: 400});
            } else {
                $(this).removeClass('is-active');
                $subNav.velocity('slideUp', {duration: 400});
            }
        });
    });
})(jQuery);
</script>

センターでマウスオーバーアコーディオン

縦センターでマウスオーバーでアコーディオン開くようにするとダイナミックな動きになりますね。

センターでマウスオーバーアコーディオンイメージ

#global-navdisplay: flexalign-items: center;で縦方向の中央揃えにできます。

CSS

#global-nav {
	text-align: center;
	height: 100%;
	display: -ms-flex;
	display: -webkit-flex;
	display: flex;
	-ms-flex-align: center;
	-webkit-align-items: center;
	align-items: center;
}

JavaScript

$('.sub-menu').on({
	'mouseenter': function () {
		$(this)
			.addClass('is-active')
			.find('.sub-menu-nav').velocity('slideDown', {
			duration: 300
		});
	},
	'mouseleave': function () {
		$(this)
			.removeClass('is-active')
			.find('.sub-menu-nav').velocity('slideUp', {
			duration: 300
		});
	}
});

マウスオーバーでサイドバーの横にスライドで開くタイプ

サブメニューの開閉自体はwdithをCSSのhoverで制御すればできますね。
サブメニューが開いているとき親のメニューもアクティブにするにはJavaScriptでクラスのON/OFFをします。

マウスオーバーでサイドバーの横にスライドで開くタイプイメージ

CSS

#global-nav .sub-menu-nav {
	position: fixed;
	background: #033560;
	color: #fff;
	top: 0;
	padding-top: 90px;
	left: 260px;
	width: 0;
	height: 100%;
	overflow: hidden;
	transition: width .2s ease-out;
}
#global-nav .sub-menu:hover .sub-menu-nav {
	width: 230px;
}

クリックでスライドして切り替わるタイプ

サブメニューが子要素にあるとオーバーフローが上手くいかないので、このパターンだけHTMLの構造を変えています。

クリックでスライドして切り替わるタイプイメージ

HTML

<aside id="sidebar">
	<nav id="global-nav">
		<ul>
			<li><a href="#">Home</a></li>
			<li class="sub-menu"><a href="#">About</a></li>
			<li class="sub-menu"><a href="#">Products</a></li>
			<li class="sub-menu"><a href="#">Link</a></li>
			<li><a href="#">Contact</a></li>
		</ul>
	</nav>
	<div id="sub-nav">
		<div id="sub-nav2" class="sub-menu-nav">
			<h3 class="sub-menu-head">About</h3>
			<ul>
				<li><a href="#">About 1</a></li>
				<li><a href="#">About 2</a></li>
			</ul>
		</div>
		<div id="sub-nav3" class="sub-menu-nav">
			<h3 class="sub-menu-head">Products</h3>
			<ul>
				<li><a href="#">Product 1</a></li>
				<li><a href="#">Product 2</a></li>
			</ul>
		</div>
		<div id="sub-nav4" class="sub-menu-nav">
			<h3 class="sub-menu-head">Link</h3>
			<ul>
				<li><a href="#">Link 1</a></li>
				<li><a href="#">Link 2</a></li>
			</ul>
		</div>
	</div>
</aside>

JavaScriptではクリック時に#sidebaris-open-submenuクラスを切り替えることでサブメニューの開閉を行います。
これだけだと全てのサブメニューが表示されてしまうので、表示するサブメニューはis-activeを付与します。

JavaScript

var $subNav = $('#sub-nav');

$('.sub-menu > a').on('click', function (e) {
	e.preventDefault();
	var index = $(this).parent().index() + 1;
	$subNav.find('#sub-nav' + index).addClass('is-active');

	$('#sidebar').addClass('is-open-submenu');
});

// サブメニューのタイトルをクリックすると閉じる
$('.sub-menu-head').on('click', function () {
	$(this).parent().removeClass('is-active');
	$('#sidebar').removeClass('is-open-submenu');
});

親の#sidebaroverflow: hiddenを指定します。

CSS

#sidebar {
	width: 260px;
	height: 100%;
	position: fixed;
	color: #fff;
	background: #033560;
	overflow: hidden;
}

#global-nav.sub-menu-navをサブメニューが開いているときleftそれぞれ移動させます。

CSS

#global-nav {
	position: relative;
	left: 0;
	transition: left .3s linear;
}
.is-open-submenu #global-nav {
	left: -100px;
}
#sub-nav .sub-menu-nav {
	position: absolute;
	top: 0;
	left: 300px;
	width: 300px;
	height: 100%;
	z-index: 2;
	transition: left .3s linear;
}
#sub-nav .sub-menu-nav.is-active {
	left: 0;
}