TOP

SassとJavaScriptで作るレスポンシブ対応のハンバーガーメニュー

SassとJavaScriptで作るハンバーガーメニュー

こんにちはゆうきです!
今回はSassとJavaScriptを使用したハンバーガーメニューを作成しました。
「Menu」「Close」で切り替わるテキスト付きなのでユーザービリティを意識したメニューを作りたい人におすすめです!

まずはデモにて、実装内容をご確認ください。

実装コード

ディレクトリ構造

├── js
│   └── common.js
├── style
│   ├── css
│   │   ├── style.css
│   │   └── style.css.map
│   └── scss
│       ├── _header.scss
│       ├── _reset.scss
│       └── style.scss
└── index.html
  • リセットCSSを設定した前提の見た目になっています。
  • Sassを使用しているので、style.cssでスタイルの変更は行わないでください。

リセットCSSは「destyle.min.css」を使用しています。

HTML

CSSとJavaScriptの読み込みは利用しているディレクトリに合わせて変更してください。

<!DOCTYPE html>
<html lang="ja">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <meta name="description" content="" />

    <!-- ##### ⬇︎ css / javascript 読み込み ⬇︎ ##### -->
    <link rel="stylesheet" href="/style/css/style.css">
    <!-- ##### ⬆︎ css / javascript 読み込み ⬆︎ ##### -->
  </head>

  <body>

    <!-- ############ header ヘッダー Start ############ -->
    <header class="header">
      <div class="header__inner">
        <h1 class="header__logo">
          <a class="header__top-link" href="/"></a>
          LOGO
        </h1>

        <!-- =========== ハンバーガーメニュー Start =========== -->
        <button class="header-hamburger" id="js-hamburger">
          <span class="header-hamburger__border"></span>
          <span class="header-hamburger__border"></span>
          <span class="header-hamburger__border"></span>
          <span class="header-hamburger__text"></span>
        </button>
        <!-- =========== /ハンバーガーメニュー End =========== -->

        <!-- =========== nav ナビゲーション Start =========== -->
        <nav class="gnav" id="js-nav">
          <ul class="gnav__list">
            <li class="gnav__item">
              <a class="gnav__link" href="#">About</a>
            </li>
            <li class="gnav__item">
              <a class="gnav__link" href="#">Works</a>
            </li>
            <li class="gnav__item">
              <a class="gnav__link" href="#">Blog</a>
            </li>
            <li class="gnav__item">
              <a class="gnav__link" href="#">Contact</a>
            </li>
          </ul>
        </nav>
        <!-- =========== /nav ナビゲーション  End =========== -->
      </div>
    </header>
    <!-- ############ /header ヘッダー End ############ -->

    <!-- ##### ⬇︎ javascript 読み込み ⬇︎ ##### -->
    <script src="/js/common.js" defer></script>
    <!-- ##### ⬆︎ javascript 読み込み ⬆︎ ##### -->
  </body>

</html>

CSS(Sass)

DartSass

2022年から@importが廃止され、@use@forwardを使用する必要がありますので、DartSass利用を前提とした解説を簡単にさせていただきます。

style.scssに@useを使用して、ハンバーガーメニューのスタイルを定義している「_header.scss」と「_reset.scss」を読み込んでいます。

@charset 'UTF8';

/* @useで読み込み */
@use "header";
@use "reset";

ハンバーガーメニューのスタイル

ハンバーガーメニューのScssになります。

768px以上のタブレットからパソコンまでのスタイルと、767px以下のスマホ画面でのスタイルを定義しています。

/* ==================================================
 768px以上(タブレット ~ PC)のスタイル
================================================== */
/* ============ ヘッダーStart ============ */
.header {
  width: 100%;
  height: 72px;
  background-color: #000;
  z-index: 999;
  position: fixed;
  color: #fff;
  display: block;

  &__inner {
    max-width: 1280px;
    padding: 0 16px;
    margin: 0 auto;
    height: 72px;
    display: flex;
    align-items: center;
  }

  &__logo {
    font-size: 24px;
  }

  // ##### ハンバーガーボタン 非表示 #####
  @media screen and (min-width: 768px) {
    .header-hamburger {
      display: none;
    }
  }
}
/* ============ ヘッダーEnd ============ */

/* ============ ナビゲーション Start ============ */
.gnav {
  margin-left: auto;
  &__list {
    display: flex;
    gap: 32px;
  }
}
/* ============ ナビゲーション End ============ */


/* ==================================================
 767px以下(スマホ)のスタイル
================================================== */
@media screen and (max-width: 767px) {

  /* ============ ハンバーガーボタン Start ============ */
  .header-hamburger {
    position: relative;
    cursor: pointer;
    background: transparent;
    margin-left: auto;
    right: 16px;
    height: 56px;
    width: 48px;

    // ##### ボタンの罫線 ここから #####
    &__border {
      position: absolute;
      left: 16px;
      width: 48px;
      height: 2px;
      background-color: #fff;
      border-radius: 2px;
      transition: all ease 0.5s;

      &:nth-of-type(1) {
        top: 8px;
      }

      &:nth-of-type(2) {
        top: 18px;
      }

      &:nth-of-type(3) {
        top: 28px;
      }
    }

    // メニューが開いてるとき
    &.is-active &__border {
      width: 40px;
      left: 45%;

      &:nth-of-type(1) {
        transform: rotate(45deg);
        top: 20px;
      }

      &:nth-of-type(2) {
        opacity: 0;
      }

      &:nth-of-type(3) {
        transform: rotate(-45deg);
        top: 20px;
      }
    }
    // ##### ボタンの罫線 ここまで #####

    // ##### ボタンのテキスト ここから #####
    &__text {
      display: block;
      position: absolute;
      font-size: 12px;
      top: 40px;
      left: 45%;
      font-weight: 600;

      &::before {
        content: 'Menu';
      }

      // テキスト「Close」(メニューが開いてるとき)
      &.is-active::before {
        content: 'Close';
      }
    }
    // ##### ボタンのテキスト ここまで #####
  }
  /* ============ ハンバーガーボタン End ============ */

  /* ============ ナビゲーション Start ============ */
  .gnav {
    transition: all 0.5s ease;
    position: fixed;
    background-color: rgba(0, 0, 0, 0.8);
    width: 100%;
    height: 100vh;
    left: 0;
    top: 72px;
    transform: translateX(100%);

    &__list {
      flex-direction: column;
      align-items: center;
      padding: 32px 0;
    }

    &.is-active {
      transform: translateX(0);
    }
  }
  /* ============ ナビゲーション End ============ */
}

JavaScript

JavaScriptでメニュー開閉時のクラスを付与しています。

document.querySelector('#js-hamburger').addEventListener('click', function () {
  this.classList.toggle('is-active');
  document.querySelector('#js-nav').classList.toggle('is-active');
  document.querySelector('.header-hamburger__text').classList.toggle('is-active');
});

コードの解説

ハンバーガーメニューの定義

「span class=”header-hamburger__border」でハンバーガーの罫線を定義し、
「span class=”header-hamburger__text”」こちらでメニューのテキスト「Menu」と「Close」をCSSを使って表示します。

<button class="header-hamburger" id="js-hamburger">
  <span class="header-hamburger__border"></span>
  <span class="header-hamburger__border"></span>
  <span class="header-hamburger__border"></span>
  <span class="header-hamburger__text"></span>
</button>

ハンバーガーメニューのCSS

768px以上の画面ではハンバーガーメニューを非表示にします。

@media screen and (min-width: 768px) {
    .header-hamburger {
      display: none;
    }
  }

767px以下の画面ではハンバーガーメニューのスタイルを定義していきます。

position: relativeを定義してspanに罫線とテキストを表示させます。

@media screen and (max-width: 767px) {

  .header-hamburger {
    position: relative;
    // ...省略

    &__border {
      position: absolute;
      left: 16px;
      width: 48px;
      height: 2px;
      background-color: #fff;
      border-radius: 2px;
      transition: all ease 0.5s;

      &:nth-of-type(1) {
        top: 8px;
      }

      &:nth-of-type(2) {
        top: 18px;
      }

      &:nth-of-type(3) {
        top: 28px;
      }
    }
  }
}

「Menu」のテキストを表示するためにCSSで文言を表示できる”content”を使用していきます。
メニューを開いた際にクラスを付与して文言を「Close」に変えるための指定になります。

    // ##### ボタンのテキスト ここから #####
    &__text {
      display: block;
      position: absolute;
      font-size: 12px;
      top: 40px;
      left: 45%;
      font-weight: 600;

      &::before {
        content: 'Menu';
      }
    }
    // ##### ボタンのテキスト ここまで #####

ハンバーガーメニューのナビゲーション

width: 100%; / height: 100vh; でメニューを開いたときに背景色を画面幅いっぱいに広げ、
top: 72pxでヘッダーと同じ高さを指定することでナビゲーションのオーバーレイが重なるのを防ぎます。

transform: translateX(100%) でナビゲーションを画面外に配置します。

.gnav {
    transition: all 0.5s ease;
    position: fixed;
    background-color: rgba(0, 0, 0, 0.8);
    width: 100%;
    height: 100vh;
    left: 0;
    top: 72px;
    transform: translateX(100%);

    &__list {
      flex-direction: column;
      align-items: center;
      padding: 32px 0;
    }

イメージ

translateX(100%) でナビゲーションを画面外に配置

JavaScriptでオープン時のclassを付与

まずはHTMLページからハンバーガーメニューのIDを取得します。

document.querySelector('#js-hamburger')

“document(HTMLページ)” の中から “#js-hamburger(ハンバーガーメニュー)” “.querySelector” で取得してきます。

メニューがクリックされた時の処理

続いて、取得したハンバーガーメニューに対してクリックされたときのイベント処理を定義

document.querySelector('#js-hamburger').addEventListener('click', function () {
});

“#js-hamburger” が “click (クリック)” されたら “function ()” 以降の処理を “.addEventListener(イベント発生)” で実行させます。

classList.toggle

“this(#js-hamburger)” に対して “.classList.toggle” でclassの切り替え処理を行います。

document.querySelector('#js-hamburger').addEventListener('click', function () {

  // 追加
  this.classList.toggle('is-active');

});

toggleメソッドの引数に対して “is-active” というメニューが開いてるときに使用するclassを定義します。
定義したclass(“is-active”)を付けたり消したりできるのが “classList.toggle”というメソッドです。

ナビゲーションとテキストにも同様の処理を追加

document.querySelector('#js-hamburger').addEventListener('click', function () {
  this.classList.toggle('is-active');

  // 追加
  document.querySelector('#js-nav').classList.toggle('is-active');
  document.querySelector('.header-hamburger__text').classList.toggle('is-active');
});

ナビゲーションとハンバーガーメニューのテキストを取得して “is-active” がついている時のclassの切り替え処理を行います。

メニューが開いているとき( .is-activeを付与)のCSS

ハンバーガーメニューのCSS

is-activeクラスが付いた際の処理を実行します。

2段目の罫線を “opacity: 0; “ で非表示にして、1段目と3段目の罫線をそれぞれ45度回転させることで、✖️ボタンに見た目を整え、”content” のテキストを「Close」に変更しています。

ハンバーガーメニュー 標準時
標準時
ハンバーガーメニュー クローズボタン
メニューオープン時
// 追加
&.is-active &__border {
      width: 40px;
      left: 45%;

      &:nth-of-type(1) {
        transform: rotate(45deg);
        top: 20px;
      }

      &:nth-of-type(2) {
        opacity: 0;
      }

      &:nth-of-type(3) {
        transform: rotate(-45deg);
        top: 20px;
      }

&__text {
      display: block;
      // 省略

    &::before {
        content: 'Menu';
      }

      // 追加
      &.is-active::before {
        content: 'Close';
      }
    }

まとめ

今回のJavaScriptの実装は「GLOBAL WEB DESIGN」さんを参考にさせていただきました。

SNSシェア

筆者プロフィール

ゆうき

新潟県出身 現在は千葉在住

アルバイトのWebデザイナー

都内のシステム会社でWebデザイナーとして勤務し、退職後は自社メディア中心のマーケティング支援会社でデザイン・ライティングなどの仕事に従事しております。
こちらのサイトでは、制作したWebサイトやデザインに関する情報を発信しております。