jQueryを使わないスマホ用横メニュー

SP用の横から出てくるナビゲーションを作成しました。
今回は練習のためにjQueryなしで作りました。一応jQueryで書いた時も載せています。
クラスと要素の追加・削除処理のみjsで行い、残りは全てcss。ハンバーガーメニューの動き部分もcssです。クラス付け替えてるだけ。

デモページ

HTML

			
			
<header class="l-header">
  <div class="header-inner inner">
    <div class="logo">header</div>
    <div id="click-nav">
      <span class="one"></span>
      <span class="two"></span>
      <span class="three"></span>
    </div>
  </div>
</header>
<div id="menu-wrap">
  <nav class="menu">
    <ul>
      <li>menu1</li>
      <li>menu2</li>
      <li>menu2</li>
      <li>menu2</li>
    </ul>
  </nav>
</div>
<div class="container">
  <div class="inner">
    container
  </div>
</div>
<footer class="l-footer">
  <div class="inner">
    footer
  </div>
</footer>

CSS

  /* base */
  body,
  html,
  ul,
  li {
    margin: 0;
    padding: 0;
  }

  ul {
    list-style-type: none;
  }

  h1 {
    display: none;
  }

  /*ここまでbase*/
  body {
    position: static;
  }

  /* body is-fixed */
  body.is-fixed {
    position: fixed;
    width: 100%;
    height: 100%;
  }

  .l-header {
    background: #b1b1b1;
    position: relative;
    z-index: 100;
  }

  .inner {
    padding: 10px;
    box-sizing: border-box;
  }

  .header-inner {
    height: 50px;
    display: -webkit-flex;
    display: flex;
    justify-content: space-between;
    -webkit-justify-content: space-between;
    -webkit-align-items: center;
    align-items: center;
  }

  .container {
    height: 800px;
  }

  .l-footer {
    height: 200px;
    background: #999;
  }

  /* menu-wrap */
  #menu-wrap {
    background: #ddd;
    width: 70%;
    position: fixed;
    top: 50px;
    right: -70%;
    height: calc(100% - 50px);
    padding: 10px;
    opacity: 0;
    visibility: hidden;
    box-sizing: border-box;
    z-index: 100;
    -webkit-transition: .3s;
    transition: .3s;
  }

  #menu-wrap.is-active {
    opacity: 1;
    visibility: visible;
    right: 0;
  }

  /* click-nav */
  #click-nav {
    position: relative;
    width: 40px;
    height: 30px;
    cursor: pointer;
  }

  #click-nav span {
    display: block;
    position: absolute;
    background: #333;
    width: 100%;
    height: 2px;
    right: 0;
    -webkit-transition: .3s;
    transition: .3s;
  }

  #click-nav .one {
    top: 0;
  }

  #click-nav .two {
    top: 14px;
  }

  #click-nav .three {
    top: 28px;
  }

  /* click-nav is-active */
  #click-nav.is-active .one {
    transform: rotate(45deg);
    top: 14px;
  }

  #click-nav.is-active .two {
    right: -50px;
  }

  #click-nav.is-active .three {
    top: 14px;
    transform: rotate(-45deg);
  }

  /* body-wrap */
  #body-wrap {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    z-index: 10;
  }

javascript

  var body = document.body;
  var nav = document.getElementById('click-nav');
  var menu = document.getElementById('menu-wrap');

  //クリックした時に発火
  nav.addEventListener('click', function() {
    action();
  }, false);

  var action = function() {

    if (nav.classList.contains('is-active')) {

      //もしclick-navにis-activeというクラスがあったら
      //(menuが開いている状態の時)
      nav.classList.remove('is-active');
      menu.classList.remove('is-active');
      body.classList.remove('is-fixed');

      //body-wrapを消す
      var wrap = document.getElementById('body-wrap');
      if (wrap.parentNode) {
        wrap.parentNode.removeChild(wrap);
      }

    } else {

      //is-activeというクラスが無かったら
      //(menuが閉じている状態の時)
      nav.classList.add('is-active');
      menu.classList.add('is-active');
      body.classList.add('is-fixed');

      //body-wrapを作る
      var element = document.createElement('div');
      element.setAttribute('id', 'body-wrap');
      body.appendChild(element);

      //body-wrapをクリックしたら
      var wrap = document.getElementById('body-wrap');
      wrap.addEventListener('click', function() {
        nav.classList.remove('is-active');
        menu.classList.remove('is-active');
        body.classList.remove('is-fixed');
        if (wrap.parentNode) {
          wrap.parentNode.removeChild(wrap);
        }
      }, false);

    }
  }

もしjQueryで書くなら

  var body = $('body');
  var nav = $('#click-nav');
  var menu = $('#menu-wrap');
  nav.on('click', function() {
    action();
  });
  var action = function() {
    if (nav.hasClass('is-active')) {
      nav.removeClass('is-active');
      menu.removeClass('is-active');
      body.removeClass('is-fixed');
      var wrap = $('#body-wrap');
      wrap.remove();
    } else {
      nav.addClass('is-active');
      menu.addClass('is-active');
      body.addClass('is-fixed');
      body.append('<div id="body-wrap" />');
      var wrap = $('#body-wrap');
      wrap.on('click', function() {
        nav.removeClass('is-active');
        menu.removeClass('is-active');
        body.removeClass('is-fixed');
        wrap.remove();
      });
    }
  }

デモページ

jQuery→javascript

jQuery便利だから使う機会が多いので、いざネイティブjavascript使おうとすると忘れている事に気がつきます・・・

onの代わりにaddEventListener

jQueryではonで様々なイベントを出せますが、ネイティブのjavascriptではaddEventListenerでイベントを追加できます。

  //クリックした時に発火 
  nav.addEventListener('click', function() {
    action();
  }, false);

appendの代わりにappendChild

要素を追加するappendの代わりにはappendChild。ただ、jQueryの様に1行では書けません。
createElementでdiv要素を作り、setAttributeでidを入れ、それからappendChildでbody要素の直下に入れます。

  //body-wrapを作る
  var element = document.createElement('div');
  element.setAttribute('id', 'body-wrap');
  body.appendChild(element);

removeの代わりにremoveChild

親要素が分かっている場合とそうでない場合で書き方が変わります。
今回使っているのは親要素が不明、不定の場合の書き方。

  var wrap = document.getElementById('body-wrap');
  if (wrap.parentNode) {
    wrap.parentNode.removeChild(wrap);
  }

参考サイト

.addEventListener() | JavaScript 日本語リファレンス | js STUDIO
Node.removeChild – Web API インターフェイス | MDN

デモページ