Skill up Log

Let's get skills with me.

【かみくだき】スライドメニュー【jQuery】

スライドメニュー
スライドメニュー

明けましておめでとうございます!今年も「Skill up Log」をよろしくお願いします。
今年は去年の2倍の記事数は書きたいと思っています。アウトプットの年にしたい!

今年から始まったかみくだき解説シリーズ第1段は、「横から出てくるスライドメニュー」について書いていきます。
前に「そうだ!ハンバーガメニューを作ろう」の記事で上から降りてくるスライドメニューについて書きましたが、今回は横バージョンです。


web-seikatsu.hatenablog.jp

去年からJavaScriptの勉強を少しずつ始めて、ソースコードを理解できてきたのでハンバーガメニューのときより詳しい解説ができると思います。
それではやっていきましょう!!

完成


まずは動きをイメージする

■図Ⅰ

スライドメニュー(クリックされる前)
スライドメニュー

  1. 「MENU」ボタンをクリックする
  2. メニューの中身がスライドで出現
  3. 「CLOSE」または背景をクリックするとメニューの中身が隠れる

■図Ⅱ

スライドメニュー
スライドメニュー(クリックされた後)

パーツごとに考える

動きのイメージができたらスライドメニューに必要なパーツを考えます。

  • MENUボタン・・・#menu_btn。
  • メニュー一覧・・・#menu。
  • メニューの背景・・・.menu-background。

HTML

ここからはソースコードの解説になります。

ポイントとなるのはメニューの部分でしょうか。
メニューのすぐ下に空のdiv.menu-backgroundがあるのですが、これがメニューがスライドしたときにメインコンテンツにかかる背景となります。

<div id="menu">
   <ul>
      <li>メニュー1</li>
      <li>メニュー2</li>
      <li>メニュー3</li>
      <li>メニュー4</li>
      <li>メニュー5</li>
    </ul>
  </div>
<div class="menu-background"></div>

CSS

CSSはポイントとなる部分がいくつかあります。
着目すべき点はpositionプロパティで書かれている箇所です。
z-indexで重なり順を指定しているのですが、そこも注意して見てください。

positionプロパティを使用しているのは「パーツごとに考える」で挙げたメニュー一覧・メニュー背景、あとはheaderです。
ひとつずつ見ていきましょう。

ヘッダー

header {
  width: 100%;
  background-color: #f390b9;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10;
}

positionプロパティにfixedを指定してスクロールされてもheaderが固定して追尾してくるようにしています。
headerのz-indexは10です。

メニュー一覧(メニューの中身)

※図Ⅰを参照。

#menu {
  width: 250px;
  height: 100%;
  background-color: #191970;
  position: fixed;
  top: 0;
  right: 0;
  z-index: 10;
  transform: translateX(250px); /* right0から250px移動した位置 */
  transition: all .5s; /* 移動する速さ */
}

メニュー一覧もpositionプロパティでfixedを指定しています。
メニュー一覧のz-indexは10です。
MENUボタンがクリックされていないときは、transformプロパティでウィンドウの一番右から250px移動した位置に配置して隠しています。
transitionプロパティでMENUボタンがクリックされたときに、メニュー一覧がスライドしてくる速度を指定しています。

クリックされた後のスタイルも見ておきましょう。

図Ⅱを参照。

#menu.open {
  transform: translateX(0); /* right0まで-250px移動 */
}

JavaScriptでMENUボタンをクリックすると、#menuにopenというクラスを付与されるのでそのスタイルを先に書いておきます。
transformプロパティで0を指定しているので、MENUボタンがクリックされるとメニューの内容が右からスライドして現れます。

メニュー背景

.menu-background {
  position: fixed;
  top: 0;
  left: 0;
  content: "";
  display: block;
  width: 0;
  height: 0;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 2;
  opacity: 0; /* 透明度を0にすることで隠す */
  transition: opacity 0.5s; /* 透明度の0→1になる速度 */
}

MENUボタンがクリックされる前は横幅・縦幅を0、opacityも0にして完全に見えなくしています。
z-indexは2です。

MENUボタンがクリックされた後のスタイルも見てみましょう。

.menu-background.open {
  width: 100%;
  height: 100%;
  opacity: 1; /* メニューが表示されているときには背景が表示 */
}

MENUボタンをクリックするとopenのクラスが付与されます。
横幅と縦幅が100%なので、openクラスが付与されたときにフワッと薄く透明がかった黒背景が浮かんでくるということですね。

重なり順は、z-indexの値が大きいほど上に重なるので
header = #menu > .menu-background > main となります。

クリックされる前とクリックされた後のスタイルができたので、JavaScriptで動きをつけていきます。

JavaScript

今回はjQueryを使うのでHTML側でjQueryを読み込む記述を書いておくのを忘れないでください。

<script src="http://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>

早速ソースコードの中身を見ていきましょう。
まずはMENUボタンがクリックされたときの処理です。

// MENUボタンがクリックされたときの処理
$('#menu_btn').on('click', function(){
  // #menu_btnに.activeがあるかどうか
  if($(this).hasClass('active')) {
    // .activeがあるときの処理
    $(this).removeClass('active'); // .activeを削除
    $(this).text('MENU'); // テキストをMENUに書き換え
    $('#menu').removeClass('open'); // #menuの.openを削除
    $('.menu-background').removeClass('open'); // .menu-backgroundの.openを削除
  } else {
    // .activeがないときの処理
    $(this).addClass('active'); // .activeを追加 
    $(this).text('CLOSE'); // テキストをCLOSEに書き換え
    $('#menu').addClass('open'); // #menuに.openを追加
    $('.menu-background').addClass('open'); // .menu-backgroundに.openを追加
  }
});

細かい処理の内容をコメントで書いておきましたので、そちらを見ていただけたら分かるかと思います。

★おおまかな処理の内容

  1. MENUボタンをクリックすると
  2. MENUがCLOSEになり、メニューの中身がスライドして出てくる
  3. メインコンテンツに薄黒い背景がかかる

CLOSEをクリックすると#menu_btnの.activeが削除され、#menu・.menu-backgroundの.openが削除されます。

これでMENUボタンをクリックしてメニューのスライドの開閉ができるようになりました!

さらにここからもうひと工夫加えます。
スライドメニューの開閉はできるようになりましたが、メニューが開いているとき背景をクリックしてもメニューを閉じたいですよね!
そこで背景をクリックしたらメニューが閉じるソースコードを書いていきます。

// メニューの背景がクリックされたときの処理
$('.menu-background').on('click', function(){
  // .menu-backgroundに.openがあるかどうか
  if($(this).hasClass('open')) {
    // .openがあるときの処理
    $(this).removeClass('open'); // .menu-backgroundの.openを削除
    $('#menu_btn').removeClass('active').text('MENU'); // ボタンのテキストをCLOSEからMENUへ書き換え
    $('#menu').removeClass('open'); // #menuの.openを削除
  }
});

★おおまかな処理の内容

  1. メニューの背景をクリックすると
  2. メニューの背景が消える
  3. メニューがスライドして消える

スライドメニューはこれで完成です。
そして最後の仕上げへ!

ヘッダーの高さへの対応

今回はメニューの中身がスライドしてくる位置をヘッダーの下にしています。
そのソースコードがこちらです。

// メインコンテンツとメニューをヘッダーの高さ分だけずらす
var headerHeight = $('header').outerHeight(); // headerの高さを取得して変数headerHeightへ代入
$('main').css('padding-top', headerHeight + 'px'); // mainのpadding-topをヘッダーの高さ分あける
$('#menu').css('margin-top', headerHeight + 'px'); // #menuのmargin-topをヘッダーの高さ分あける

mainと#menuのスタイルをCSSで、ヘッダーの高さ分のpxを書かないでJavaScriptで書いているのかというとレスポンシブのためです。
バイスによってheaderの高さが可変しても、可変したデバイスでのheaderの高さを取得するので変な余白やズレが起きるのを防ぐためです。

以上になります。
今回は自分なりにできるだけかみくだいて書きました。参考にしていただけると幸いです。

■参考にした記事
tivel.jp