現場でよく使うjQueryを用いたハンバーガーメニューを作ってみた(備忘録)

前回書いた下記の記事のソースを流用して、今回は、現場でよく使っているjQueryを用いたハンバーガーメニューを作ってみた。

今回は3本線のメニューではなく、2本線に文字を入れたパターンで作ってみることにした。

前回の記事はこちら

今回も、前回の記事と重なっている部分の説明は省略することにするが、ソースは全て載せるので、コピペすれば実装できるかと思う。

では、実装に入っていきたいと思う。

htmlの記述について

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="robots" content="index, follow" />
  <title>ハンバーガーメニュー</title>
  <link rel="stylesheet" href="../reset.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <!-- ハンバーガーメニュー -->
    <!-- 線 -->
    <div id="bl_hamburgerLine" class="hp_displaySP">
      <span></span>
      <span></span>
      <p>menu</p>
    </div>
    <!-- メニューの中身 -->
    <nav id="bl_hamburgerMenu">
      <ul class="bl_hamburgerMenu_list" id="bl_hamburgerLink">
        <li><a href="#menu1">menu1</a></li>
        <li><a href="#menu2">menu2</a></li>
        <li><a href="#menu3">menu3</a></li>
        <li><a href="#menu4">menu4</a></li>
        <li><a href="#menu5">menu5</a></li>
      </ul>
    </nav>
    <!-- //ハンバーガーメニュー -->
  </header>
  <main>
    <section>
      <div class="ly_mainvisual">
        <img src="img_mainvisual.jpg" alt="MV">
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu1">
        <h2>menu1</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu2">
        <h2>menu2</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu3">
        <h2>menu3</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu4">
        <h2>menu4</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu5">
        <h2>menu5</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
  </main>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="style.js"></script>
</body>
</html>

以前と変わった部分は、ハンバーガーメニューの線の部分である。

 <div id="bl_hamburgerLine" class="hp_displaySP">
   <span></span>
   <span></span>
   <p>menu</p>
 </div>

2本線の下に「menu」のテキストが表示されるように修正している。

cssの記述について

@charset "utf-8";

/* ==========================
  初期設定
========================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}
img {
  width: 100%;
}

/* ==========================
  コンテンツの中身
========================== */
.ly_inner {
  width: 100%;
  max-width: 1080px;
  margin: 100px auto;
  padding: 20px;
  background-color: #ccc;
}
.ly_inner h2 {
  font-size: 150%;
  font-weight: bold;
  margin-bottom: 30px;
}
.md_textblock > * + * {
  margin-top: 10px;
}
/* ====================================
  ここからPC幅
==================================== */
@media screen and (min-width: 768px) {
  .hp_displaySP {
    display: none !important;
  }
  /* ナビゲーション */
  header {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 38px;
    background-color: #222;
  }
  .bl_hamburgerMenu_list {
    display: flex;
    text-align: center;
    align-items: center;
    width: 100%;
  }
  .bl_hamburgerMenu_list > li {
    width: 100%;
    padding: 10px 5px;
  }
  .bl_hamburgerMenu_list > li a{
    color: #fff;
  }

}

/* ====================================
  ここからスマホ幅
==================================== */
@media screen and (max-width: 767px) {
  .hp_displayPC {
    display: none !important;
  }
  /* ==========================
    ハンバーガーメニュー
  ========================== */
  header {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 60px;
    background-color: grey;
  }
  /* 線 */
  #bl_hamburgerLine {
    position: absolute;
    right: 0;
    top: 0;
    width: 36px;
    height: 60px;
    margin: 0 15px;
    cursor: pointer;
    z-index: 1000;
  }
  #bl_hamburgerLine span {
    display: block;
    position: absolute;
    right: 0;
    background-color: #444;
    height: 2px;
    width: 100%;
    transition: .3s;
  }
  #bl_hamburgerLine span:first-of-type {
    top: 10px;
  }
  #bl_hamburgerLine span:last-of-type {
    top: 30px;
  }
  #bl_hamburgerLine p {
    position: relative;
    top: 40px;
    text-align: center;
    font-size: 80%;
  }
  /* クリックした時 */
  #bl_hamburgerLine.active {
    z-index: 1001;
  }
  #bl_hamburgerLine.active span {
    background-color: #fff;
  }
  #bl_hamburgerLine.active span:first-of-type {
    transform: rotate(-135deg);
    top: 20px;
  }
  #bl_hamburgerLine.active span:last-of-type {
    transform: rotate(135deg);
    top: 20px;
  }
  #bl_hamburgerLine.active p {
    font-size: 0;
  }
  #bl_hamburgerLine.active p::before {
    content: "close";
    font-size: 14px;
    color: #fff;
    position: relative;
    top: -2px;
  }
  /* ハンバーガー展開時の中身 */
  #bl_hamburgerMenu {
    display: none;
    position: absolute;
    width: 100%;
    background-color: grey;
    color: #fff;
    font-size: 24px;
    padding: 100px 15px;
    height: 100vh;
    overflow-y: scroll;
  }
  .bl_hamburgerMenu_list {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
  }
  .bl_hamburgerMenu_list li+li {
    margin-top: 20px;
  }
}

今回は、スマホのヘッダーに色をつけることにした。その上にハンバーガーメニューの線がのるように対応している。

今回はjQueryのslideToggleを用いてハンバーガーメニューの開閉対応をするため、前回指定していたopacityやoverflowを用いて透明不透明にするcssは削除している。

slideToggleを用いると、ページを読み込んだ時に指定した要素がdisplay:none;になり、クリックしてからdisplay:block;に変わるようになっている。

このため、その要素に対してflexなどを指定しているとうまく動かなくなるので、それを回避するために、一部のcssを調整している。

その他、ハンバーガーメニューの「menu」テキストが、クリックしてから「close」に変わるようcssで調整した。クリックしてからのmenuのフォントサイズを0にし、擬似要素でcloseの文字を指定し、大きさや色などを変える対応をしている。

javascriptの記述について

'use strict';

// 以下でPC幅とスマホ幅で出し分けするための準備をする
const deviceWidth = function (e) {
  if (window.matchMedia("(max-width:767px)").matches && "sp" === e)
  return !0;
  return !!(window.matchMedia("(min-width:768px)").matches && "pc" === e)
};

// ハンバーガーメニュー
$(function () {
  void 0,
  deviceWidth("sp") && (
    $("#bl_hamburgerLine").click(function () {
      $(this).toggleClass("active"),
        $(this).next().slideToggle(300)
    }),
    $("#bl_hamburgerMenu li a").click(function () {
      $("#bl_hamburgerLine").toggleClass("active"),
        $(this).parent().parent().parent().slideToggle(300)
    })
  )
});

// スムーススクロール
$(window).on("load", function () {
  let headerHeight = $("header").outerHeight();
  $("a").click(function () {
    var a = $(this).attr("href")
      , targetElement = $("#" === a || "" === a ? "html" : a)
      , moveDistance = targetElement.offset().top - headerHeight;
    return $("body,html").animate({
      scrollTop: moveDistance
    }, 400, "swing"),
      !1
  });
  var a = location.hash;
  if (a) {
    var targetElement = $(a).offset().top - headerHeight;
    $("html, body").animate({
      scrollTop: targetElement
    }, 400)
  }
});

今回は、内容が大きく変更している。

PC幅とスマホ幅で事前に定数を宣言しておくことであとの記述で使いまわせるようにしておく

deviceWidth、sp、pc、767、768の値や文字は、任意の値や文字に変えていただいて大丈夫だ。

実際に使うときは、deviceWidth(“sp”)、deviceWidth(“pc”)と指定すると、使いたい幅で記述していくことができるので、毎回出しわけの記述を書く手間が省略できる。

jQueryのtoggleClassとslideToggleを用いたハンバーガーメニューの実装

void 0というのは、aリンクをクリックした時に他のページに遷移しないようにするための記述である。

続いて、deviceWidth(“sp”) &&の記述によって、スマホ幅の時だけの内容を書いていくことができる。

$("#bl_hamburgerLine").click(function () {
  $(this).toggleClass("active"),
    $(this).next().slideToggle(300)
})

この記述については、#bl_hamburgerLineをクリックしたときの内容が書かれている。ここにthisが2つあるが、これは#bl_hamburgerLineを指している。

toggleClassはクリックしたときに、#bl_hamburgerLineに対して任意のクラスをつけることができる。今回はactiveを指定している。もう一度クリックするとactiveのクラスが外れるようになっている。

一方slideToggleについては、どのくらいの時間や変化をかけて隠れていた要素が下方向に降りて表示させるか、また、降りてきたものを元の折り畳んだ状態にするなどが実装できるものになる。

nextというものが出ているが、これは#bl_hamburgerLineの次の兄弟要素を指定するために使っている。今回のhtmlでは#bl_hamburgerMenu を指定していることになる。

この辺りの指定は、オリジナルにカスタマイズしてハンバーガーメニューを作りたいときに、理解できていないとつまずくポイントになるので、注意しておきたいところだ。

$("#bl_hamburgerMenu li a").click(function () {
  $("#bl_hamburgerLine").toggleClass("active"),
    $(this).parent().parent().parent().slideToggle(300)
})

続いては、aリンクをクリックした時に、ハンバーガーメニューが解除されるように、また、開いていたハンバーガーメニューが閉じていくような実装をしている。

thisは、#bl_hamburgerMenu li aを指している。直前の#bl_hamburgerLineではないことに注意しておきたいところだ。

parentについては、先ほどのnextとも絡んでくるところだが、親要素を見ていくことになる。

今回は、3回指定が入っているため、aから3回辿っていくと、#bl_hamburgerMenuが指定されることがわかる。

slideToggleの括弧の中には、秒数であったり、slowやfastなどを指定することができる。これにより展開する速さを調整できる。ググれば色々出てくるので、調べて見てほしい。

スムーススクロールについて

// スムーススクロール
$(window).on("load", function () {
  let headerHeight = $("header").outerHeight();
  $("a").click(function () {
    var a = $(this).attr("href")
      , targetElement = $("#" === a || "" === a ? "html" : a)
      , moveDistance = targetElement.offset().top - headerHeight;
    return $("body,html").animate({
      scrollTop: moveDistance
    }, 400, "swing"),
      !1
  });
  var a = location.hash;
  if (a) {
    var targetElement = $(a).offset().top - headerHeight;
    $("html, body").animate({
      scrollTop: targetElement
    }, 400)
  }
});

今回は、値を直接入れなくてもヘッダーの高さを計算できるようにしている。決まり文句的な宣言なので、丸暗記する必要はないかと思う。

headerHeightでヘッダーの高さを算出。

あとはページ内の全てのa要素を探してきて、アンカーリンクが設定されているものを見つけ出し、距離を測ってどのくらい動かすが決めているという感じだ。

moveDistanceでヘッダー分の高さを引くことで、スクロールした時に見出しが見えなくならないように調整している。

400の値は0.4秒かけてその処理が行われるので、この値を変更すればスクロールの秒数をコントロールできる。

今回のハンバーガーメニューシリーズはこれで以上にしたいが、学習していく中で、もう少しましな方法が見つかれば、本記事も更新したいと思う。

2 返信

コメントはクローズされています。