【Bootstrap+Drawer.js】Drawerメニュー内にBootstrapのNavbarメニューを組み込む

表題の通り、Drawer.jsによりスライドインするメニューの中で、Bootstrapのnavbarを使い開閉可能なサブメニューを実装します。

また、Drawer.jsを使うと実機で見たときにスクロールが正しく機能しなくなったので、そのときにとった対応をメモしておきます。

まずはBootstrapのnavbarとDrawer.jsについて簡単に説明します。

はじめに

Bootstrap navbarについて

Bootstrapのnavbarは開閉式のメニューを作るのに利用します。

公式 : https://getbootstrap.jp/docs/4.2/components/navbar/

メニューの開閉のコントロールをボタンで行っていますが、テキストにすることもできるので「メインメニュー > サブメニュー」のように実装することも可能です。

実装例 [クリックで表示]

上記イメージの実装が以下のようになります。

開閉ボタンにbuttonタグを使用していますが、これは何でもよくてdata-target属性にcollspaceクラスを持つコンテンツのid属性と併せておけばOKです。

<nav class="navbar navbar-light navbar-expand-md p-1">
  <div class="navbar-brand sp"></div>
  <button class="navbar-toggler" type="button"
    data-toggle="collapse"
    data-target="#navmenu"
    aria-controls="navmenu"
    aria-expanded="false"
    aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navmenu">
    <ul class="navbar-nav flex-column">
      <a href="#"><li class="nav-item nav-link text-center">
        <span>ITEM-1</span>
      </li></a>
      <a href="#"><li class="nav-item nav-link text-center">
        <span>ITEM-2</span>
      </li></a>
      <a href="#"><li class="nav-item nav-link text-center">
        <span>ITEM-3</span>
      </li></a>
      <a href="#"><li class="nav-item nav-link text-center">
        <span>ITEM-4</span>
      </li></a>
    </ul>
  </div>
</nav>
          

Drawer.jsについて

Drawer.jsを使うと右からスライドインするメニューを作ることがきでます。

公式 : https://git.blivesta.com/drawer/

実装例 [クリックで表示]

<div class="drawer drawer--right drawer-close">
  <header>
    <button type="button" id="drawer-menu-button" class="drawer-toggle drawer-hamburger">
      <span class="sr-only">toggle navigation</span>
      <span class="drawer-hamburger-icon"></span>
    </button>
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">TEST</a>
        </div>
      </div>
    </nav>
    <nav class="drawer-nav">
      <ul class="drawer-menu">
        <li><a href="#">MENU-1</a></li>
        <li><a href="#">MENU-2</a></li>
        <li><a href="#">MENU-3</a></li>
        <li><a href="#">MENU-4</a></li>
        <li><a href="#">MENU-5</a></li>
        <li><a href="#">MENU-6</a></li>
        <li><a href="#">MENU-7</a></li>
        <li><a href="#">MENU-8</a></li>
        <li><a href="#">MENU-9</a></li>
        <li><a href="#">MENU-10</a></li>
        <li><a href="#">MENU-11</a></li>
        <li><a href="#">MENU-12</a></li>
        <li><a href="#">MENU-13</a></li>
        <li><a href="#">MENU-14</a></li>
        <li><a href="#">MENU-15</a></li>
        <li><a href="#">MENU-16</a></li>
        <li><a href="#">MENU-17</a></li>
        <li><a href="#">MENU-18</a></li>
        <li><a href="#">MENU-19</a></li>
        <li><a href="#">MENU-20</a></li>
      </ul>
    </nav>
  </header>
</div>
<script type="text/javascript">
$(function() {
  $(document).ready(function() {
    $('.drawer').drawer();
  });
});
</script>
          

この2つを組み合わせて右からスライドするメニュー内にハンバーガー式のサブメニューを内蔵させたDrawerメニューを作っていきます。

スライドインするハンバーガー式メニュー

実装

まずは単純に上記の実装例の2つを組み合わせてみます。

drawer-menu内にnavbarを入れます。この際メニューを開いたらボタンを押して更にメニューを開くというのはおかしいので、type="button" をやめて、 class="navbar-brand" を設定します。これによりメニューを開いたら「メインメニューをクリックしてサブメニューを開く」という構成になります。

また、navbarメニューを複数設定する場合は data-target="#navmenu" を変更してそれぞれ開きたいサブメニューのidを指定します。

実装例 [クリックで表示]

<nav class="drawer-nav">
  <ul class="drawer-menu">
    <li>
      <nav class="navbar navbar-light navbar-expand-md p-1">
        <div
          class="navbar-brand"
          data-target="#navmenu1"
          data-toggle="collapse">MENU-1</div>
        <div class="collapse navbar-collapse" id="navmenu1">
          <ul class="navbar-nav flex-column">
            <a href="#"><li class="nav-item nav-link text-left">
              <span>ITEM-1</span>
            </li></a>
            <a href="#"><li class="nav-item nav-link text-left">
              <span>ITEM-2</span>
            </li></a>
            <a href="#"><li class="nav-item nav-link text-left">
              <span>ITEM-3</span>
            </li></a>
            <a href="#"><li class="nav-item nav-link text-left">
              <span>ITEM-4</span>
            </li></a>
          </ul>
        </div>
      </nav>
    </li>
  </ul>
</nav>

スクロールが効かない問題

上記のサンプルでは確認しにくいですが、サブメニューをすべて開いて高さが画面サイズを超えたときスクロールが効かなくなります。

メニューを開き直すとスクロールが効いているように見えますが、実機で確認すると全く効きませんのでこれを解決するために行った修正を以下にまとめます。

CSS

まずはCSSに以下を追加します。

.drawer-nav > .drawer-menu {
  overflow-y: scroll;
  -webkit-overflow-scrolling: auto;
}

drawer-toggleクラスを廃止

原因としてはDrawer.jsのボタンに設定しているdrawer-toggleを使用しているとスクロールの挙動がおかしくなるのでこれをやめました。

一旦 drawer-toggle → drawer-toggle-test などと変更します。これによりメニューボタンを押しても開かなくなるのですが、ここの処理はjQueryを使って自前で用意します。

jQuery

  // メニューボタン
  var scrollPos;
  $('#drawer-menu-button').on('click', function() {
    if ($('.drawer').hasClass('drawer-close')) {
      $('.drawer').removeClass('drawer-close');
      $('.drawer').addClass('drawer-open');
      scrollPos = $(window).scrollTop();
      $('body').addClass('fixed').css({'top': -scrollPos});
    } else {
      $('.drawer').removeClass('drawer-open');
      $('.drawer').addClass('drawer-close');
      $('body').removeClass('fixed').css({'top': 0});
      window.scrollTo(0, scrollPos);
    } 
  }); 

このようにすれば自前でDrawerメニューの開閉ができます。bodyに追加してるfixedはメニューを開いて操作しているときに後ろの画面が動かないようにするためです。

サンプル

最後に実装サンプルを載せておきます。

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap Navigation + Drawer.js TEST</title>
    <meta http-equiv="content-style-type" content="text/css">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/drawer/3.1.0/css/drawer.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/iScroll/5.1.3/iscroll.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/drawer/3.1.0/js/drawer.min.js"></script>
<style type="text/css">
body {
  background-color: #ccc;
}
nav {
  background-color: #fff;
}
.drawer-menu li {
  margin-top: 20px;
  margin-left: 20px;
}

.drawer-nav > .drawer-menu {
  height: 96%;
  overflow-y: scroll;
  -webkit-overflow-scrolling: auto;
}
</style>
<script type="text/javascript">
$(function() {
  $(document).ready(function() {
    $('.drawer').drawer();
  });

  // メニューボタン
  var scrollPos;
  $('#drawer-menu-button').on('click', function() {
    if ($('.drawer').hasClass('drawer-close')) {
      $('.drawer').removeClass('drawer-close');
      $('.drawer').addClass('drawer-open');
      scrollPos = $(window).scrollTop();
      $('body').addClass('fixed').css({'top': -scrollPos});
    } else {
      $('.drawer').removeClass('drawer-open');
      $('.drawer').addClass('drawer-close');
      $('body').removeClass('fixed').css({'top': 0});
      window.scrollTo(0, scrollPos);
    }
  });
});

</script>
  </head>
  <body>

<div class="drawer drawer--right drawer-close">
  <header>
    <button type="button" id="drawer-menu-button" class="drawer-toggle-test drawer-hamburger">
      <span class="sr-only">toggle navigation</span>
      <span class="drawer-hamburger-icon"></span>
    </button>
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a class="navbar-brand" href="/">TEST</a>
        </div>
      </div>
    </nav>
    <nav class="drawer-nav">
      <ul class="drawer-menu">
        <li>
          <div
            class="navbar-brand"
            data-target="#navmenu1"
            data-toggle="collapse">MENU-1</div>
          <nav class="navbar navbar-light navbar-expand-md p-1">
            <div class="collapse navbar-collapse" id="navmenu1">
              <ul class="navbar-nav flex-column">
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-1</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-2</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-3</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-4</span>
                </li></a>
              </ul>
            </div>
          </nav>
        </li>
        <li>
          <div
            class="navbar-brand"
            data-target="#navmenu2"
            data-toggle="collapse">MENU-2</div>
          <nav class="navbar navbar-light navbar-expand-md p-1">
            <div class="collapse navbar-collapse" id="navmenu2">
              <ul class="navbar-nav flex-column">
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-1</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-2</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-3</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-4</span>
                </li></a>
              </ul>
            </div>
          </nav>
        </li>
        <li>
          <div
            class="navbar-brand"
            data-target="#navmenu3"
            data-toggle="collapse">MENU-3</div>
          <nav class="navbar navbar-light navbar-expand-md p-1">
            <div class="collapse navbar-collapse" id="navmenu3">
              <ul class="navbar-nav flex-column">
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-1</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-2</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-3</span>
                </li></a>
                <a href="#"><li class="nav-item nav-link text-left">
                  <span>ITEM-4</span>
                </li></a>
              </ul>
            </div>
          </nav>
        </li>
      </ul>
    </nav>
  </header>
</div>

  </body>
</html>

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)