読者です 読者をやめる 読者になる 読者になる

yuri memo

コーディングとかのメモ帳

スマホでフルスクリーンになるレスポンシブメニュー

今回は以下のようなレスポンシブメニューを実装しました。
・モバイル時に、メニューをフルスクリーンで表示
・メニュー開閉アニメーションはフェードイン/フェードアウト
jQueryのfadeToggleなどは使わずに、classの付け外しをjQueryで行う

デモはこちらです。

yuri memo - レスポンシブメニュー DEMO
 デモは、以下のような構成になっています。
HTML
[ fade_menu.html ]
CSS
[ css/style.css ]
jQuery
[ js/jquery-2.0.0.min.js ]
[ js/script.js ]

HTML

順番にコードを載せていきます。

<body>
  <header>
    <h1 class="logo">yuri memo</h1>
    <!-- ハンバーガーメニュー部分 -->
    <div id="toggle">
      <div class="trigger">
        <span></span>
        <span></span>
        <span></span>
      </div>
    </div>

    <!-- フルスクリーン部分 -->
    <div class="toggleWrap">
      <!-- メニュー部分 -->
      <ul class="mainNav">
        <li><a class="navItem" href="#">Home</a></li>
        <li><a class="navItem" href="#">About</a></li>
        <li><a class="navItem" href="#">Product</a></li>
        <li><a class="navItem" href="#">Contact</a></li>
        <li><a class="navItem" href="#">Nyaaan</a></li>
      </ul>
    </div>
  </header>

  <main>
    <h2>レスポンシブメニューのデモです。</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  </main>

  <!-- jsファイルの読み込み -->
  <script type="text/javascript" src="js/jquery-2.0.0.min.js"></script>
  <script type="text/javascript" src="js/script.js"></script>
</body>

#toggleがクリックされた時に、
.toggleWrapに対して、開閉のクラスやアニメーションのクラスをつけていきます。

CSS

※メニューに関するCSSのみ抜粋しています。
CSSの全コードはデモから確認できます。

/* スマホでメニューを開いた際に背景色が画面全体にかかるようにと
フルスクリーンで固定したいので、position: fixed; top: 0; left: 0; を指定 */
.toggleWrap {
  background: rgba(234, 234, 234, 0.95);
  padding: 50px 15px 10px 15px;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.mainNav li {
  list-style-type: none;
}
.navItem {
  display: block;
  text-decoration: none;
  color: #3e3e3e;
  border-bottom: 1px solid #ccc;
  padding: 15px 0;
  text-align: center;
  font-size: 2rem;
}

/* メニューを閉じる時のスタイル
display:none; を使用せず、opacityを使うとfadeっぽくなる */
.hide {
  opacity: 0;
  visibility: hidden;
  overflow: hidden;
}

/* アニメーションはメニューの開閉時のみでいいので
.toggleWrapに書かず、別にclassを用意 */
.animation {
  -webkit-transition-property: opacity, visibility;
  transition-property: opacity, visibility;
  -webkit-transition-duration: .3s;
          transition-duration: .3s;
  -webkit-transition-timing-function: ease-in;
          transition-timing-function: ease-in;
}

/* メニューオープン時のみ、メニューの後ろのコンテンツをスクロールさせない
iOS safariには別途対応が必要(jQueryに記述)*/
.no-scroll {
  overflow: hidden;
}

/* 768px以上に適応するスタイル */
@media screen and (min-width: 768px) {
  #toggle {
    display: none;
  }
  .toggleWrap {
    background: none;
    height: auto;
    position: static;
    padding: 0;
    margin-bottom: 20px;
  }
  .mainNav {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: justify;
    -webkit-justify-content: space-between;
       -ms-flex-pack: justify;
            justify-content: space-between;
    max-width: 670px;
    margin: 0 auto;
  }
  .navItem {
    padding: 5px 15px;
  }
  .navItem:hover {
    border-color: #3696da;
  }
  .animation {
  -webkit-transition: none;
          transition: none;
  }

 /* 非表示にしていたメニューを表示させる */
  .hide {
    opacity: 1;
    visibility: visible;
  }
}

jQuery

$(function(){
  fade('.toggleWrap');
});

function fade(elm){
  var $fade = $(elm),
      $body = $('body');
  // .toggleWrapを非表示にしておく
  $fade.addClass('hide');

  // #toggleがクリックされた時に、.hideの付け外しで .toggleWrapの表示・非表示を切り替え
  // .addClass('animation');でアニメーションのCSSを適応
  $('#toggle').on('click', function(){
    $fade.toggleClass('hide').addClass('animation');
    $('.trigger').toggleClass('active');

    // スクロールの制御
    // .hideを持っている状態はメニューが閉じている状態で、このときは.no-scrollは不要
    if ($fade.hasClass('hide')) {
      $body.removeClass('no-scroll').off('.noScroll');
    } else {
      // メニューが開いている時に、bodyに.no-scrollを追加してスクロールさせない
      $body.addClass('no-scroll').on('touchmove.noScroll', function(e){
        e.preventDefault();
      });
    }
  });
}
$body.on('touchmove.noScroll', function(e){
  e.preventDefault();
});

上記の部分はiOSでは、overflow: hidden;だけでスクロールを無効にできないため追記しています。
こちらの記事が参考になりました。
qiita.com

fadeToggleを使わない理由

jQueryでslideToggleとかfadeIn,fadeOutとか楽なのは事実なんですが
fadeOutは最終的にdisplay: none;の状態になります。
CSSでdisplay: block;とか書いてても
style属性にdisplay: none;が適応されているので
リロードしないとその状態が保持されたままなんですよね(._.)
こんな感じです。ブレイクポイントを過ぎてもメニューが表示されませんね。
http://yurixxx8.com/demo/20170305/2017-03-05.gif
ブレイクポイントによってはスマホの縦横切り替えでこの現象が起きるかも?
なので今回はクラスの付け外しでやってみました!

以上ですにゃ。