WEBOPIXEL

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

Posted: 2018.04.27 / Category: javascript / Tag: ,

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

Sponsored Link

基本構造

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

HTML

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
<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

1
2
3
4
5
6
7
8
9
10
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
(function($) {
    $(function () {
        $('.sub-menu').on('click', function (e) {
            e.preventDefault();
            var $subNav = $('.sub-menu-nav', this);
            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

1
2
3
4
5
6
7
8
9
10
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$('.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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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

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
<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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
#sidebar {
    width: 260px;
    height: 100%;
    position: fixed;
    color: #fff;
    background: #033560;
    overflow: hidden;
}

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

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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;
}