【初〜中級者向け】バーガーメニューの自作り方

最近フロントばっかりやっているので、すっかりフロント脳になってます。
たまにサーバサイドやるとポンコツになっているのがよく分かりますね。

 

さて、以前プラグインを使ったバーガーメニューの実装について記事を書いたんですが、今回はHTML(PHP)+CSS+jQueryを使って、バーガーメニューを自作する方法について書いてみようと思います。

自作できるとデザインや動きのカスタマイズの幅が一気に拡がりますし、意外と簡単にできるので、備忘録的に残しておこうと思います。

WordPress専用って部分はほとんどないので、色々と使い回せると思います。

 

今回作るのはこんな感じ↓↓のバーガーメニューです。
サイズ感や色などにはあまり言及しないで進めていきます。

 

ちょっと長いですが、まずはスクリプトのサンプルから。

 

HTML(PHP)

<header>
  <div class="header-container">
    <div class="burger-menu">
      <div class="burger-menu-container">
        <div class="burger-menu-button"></div>
        <div class="burger-menu-text show">MENU</div>
        <div class="burger-menu-text-close">CLOSE</div>
      </div>
    </div>

    <div class="dropdown hide">
      <?php
        wp_nav_menu(
          array(
            'menu' => 'main',
            'container' => 'div',
            'container_class' => 'dropdown-container',
            'items_wrap' => '<ul class="dropdown-menu">%3$s</ul>'
          )
        );
      ?>
    </div>

	</div>
</header>

 

CSS

/* ===========================================================*/
/* Common */
/* ===========================================================*/

  .header-container {
    position: fixed;
    transition: 0.5s;
    width: 100%;
    padding: 10vw 0;
  }

/* ===========================================================*/
/* Burger Menu */
/* ===========================================================*/

  .burger-menu {
    position: absolute;
    top:  9vw;
    left: 4vw;
    width:  7.5vw;
    height: 7.5vw;
    transition: 0.5s;
  }

  .burger-menu:hover {
    opacity: 0.7;
    cursor: pointer;
  }

  .burger-menu-container {
    position: relative;
    width:  100%;
    height: 100%;
  }

  .burger-menu-button,
  .burger-menu-button:before,
  .burger-menu-button:after {
    width:  6.5vw;
    height: 0.8vw;
    background-color: #333;
    border-radius: 0.5vw;
    position: absolute;
    transition: transform 0.25s ease-in-out;
  }

  .burger-menu-button {
    top: 50%;
  }

  .burger-menu-button:before {
    content: "";
    top: -2vw;
  }

  .burger-menu-button:after {
    content: "";
    bottom: -2vw;
  }

  .burger-menu-button.transform:before {
    transform: translateY(2vw);
  }

  .burger-menu-button.transform:after {
    transform: translateY(-2vw);
  }

  .burger-menu-button.transform2 {
    transform: rotate(-135deg);
  }

  .burger-menu-button.transform2:before {
    opacity:0;
  }

  .burger-menu-button.transform2:after {
    transform: translateY(-2vw) rotate(270deg);
  }

  .burger-menu-text,
  .burger-menu-text-close {
    top:  1.4vw;
    left: 8vw;
    position: absolute;
    font-size: 3.6vw;
    color: #999;
    opacity: 0;
    transition: all 0.3s ease-in-out;
  }

  .burger-menu-text {
    transform: translateY(-5vw);
  }

  .burger-menu-text-close {
    transform: translateY(5vw);
  }

  .burger-menu-text.show,
  .burger-menu-text-close.show {
    opacity: 1;
    transform: none;
  }

/* ===========================================================*/
/* Dropdown Menu */
/* ===========================================================*/

  .dropdown {
    position: absolute;
    top: 27.5vw;
    left: 0;
    width: 100%;
    transition: 0.5s;
    box-shadow: 2.5vw 2.5vw 2.5vw 0 rgba(102,102,102,0.5);
  }

  .dropdown.transform {
    top: 10.1vw;
    transition: 0.4s ease-out;
  }

  .dropdown.hide {
    transform: translateY(-170%) ;
    transition: 0.4s ease-in;
  }

  .dropdown-menu {
    margin: 0;
    padding: 0;
  }

  .dropdown-menu li {
    list-style: none;
    width: 100%;
    background-color: #fff;
    border-bottom: 0.5vw solid #999;
  }

  .dropdown-menu li:first-child {
    border-top: 0.5vw solid #999;
  }

  .dropdown-menu li a {
    width: 100%;
    height: 100%;
    display: block;
    background-color: #ccc;
    color: #333;
    font-size: 4vw;
    line-height: 12.5vw;
  }

  .dropdown-menu li.current_page_item a {
    background-color: #ddd;
    color: #999;
  }

  .dropdown-menu li a i {
    margin: 0 0 0 4vw;
  }

jQuery

jQuery(function($){

// バーガーメニューをクリックしたらメニュー表示・非表示を切り替え
    $('.burger-menu').on('click', function(){
        if ( $('.burger-menu-button').hasClass('transform') ) {
            $('.burger-menu-button').toggleClass('transform2');
            setTimeout(function(){
                $('.burger-menu-button').toggleClass('transform');
                $('.dropdown').toggleClass('hide');
            },250);
        } else {
            $('.burger-menu-button').toggleClass('transform');
            setTimeout(function(){
                $('.burger-menu-button').toggleClass('transform2');
                $('.dropdown').toggleClass('hide');
            },250);
        }
        setTimeout(function(){
            $('.burger-menu-text').toggleClass('show');
            $('.burger-menu-text-close').toggleClass('show');
        },250);
    })

// メニュー表示中にメニュー以外の場所をクリックしたらメニュー非表示
    $(document).on('click touchend', function(event) {
      if (!$(event.target).closest('.burger-menu').length) {
        $('.burger-menu-button').removeClass('transform2');
        setTimeout(function(){
            $('.burger-menu-button').removeClass('transform');
            $('.dropdown').addClass('hide');
        },250);
        setTimeout(function(){
            $('.burger-menu-text').addClass('show');
            $('.burger-menu-text-close').removeClass('show');
        },250);
      }
    });
});

 

 

ポイントと言えるのは、5つくらいでしょうか。

 

①WordPressに登録したメニューを呼び出して描画
HTMLの12〜21行目の部分です。
wp_nav_menu()という関数を使って、mainという名前のメニューを呼び出しています。

だいたい想像つくかもしれませんが、引数の意味はこんな感じです。

'menu' => 'main',  // mainという名前のメニューを指定
'container' => 'div',  // メニュー全体をくくるタグを指定
'container_class' => 'dropdown-container',  // そのタグのクラス名を指定
'items_wrap' => '<ul class="dropdown-menu">%3$s</ul>'  // 1つ1つのメニューを出力するリストタグ(「%3&s」部分にメニューが出力されます)

 

②3本線メニューの正体
2つ目はCSSの36〜59行目の部分。
バーガーメニューではおなじみの3本線は本体、before、afterの3つを使って表現しています。
初めて知った時には「こんな作り方してたんだ…」って軽い衝撃でした。

/* ここが3本線の共通部分 */
  .burger-menu-button,
  .burger-menu-button:before,
  .burger-menu-button:after {
    width:  6.5vw;  /* 3本線の1本の横幅、 */
    height: 0.8vw;  /* 太さ、 */
    background-color: #333;  /* 色をそれぞれ表しています。 */
    border-radius: 0.5vw;
    position: absolute;
    transition: transform 0.25s ease-in-out;
  }

/* 3本線の真ん中。 */
  .burger-menu-button {
    top: 50%;
  }

/* 3本線の上。beforeやafterは本体の位置指定に引っ張られるので注意 */
  .burger-menu-button:before {
    content: "";
    top: -2vw;
  }

/* 3本線の下。before、afterはcontent: "";がないと現れないということにも注意 */
  .burger-menu-button:after {
    content: "";
    bottom: -2vw;
  }

 

③メニューの表示・非表示アニメーション
CSSのtransformの指定を変えれば、いろんな登場のさせ方ができますね。
今回のメニューは上からガラガラって降りてくるタイプです。

jQuery4行目の

$('.burger-menu').on('click', function(){

は「バーガーボタンがクリックされたら発動する」の部分。

 

9行目、15行目の

$('.dropdown').toggleClass('hide');

は「dropdown」というクラスを持った要素に「hide」というクラスを付けたり、外したりします。

 

これによって、バーガーボタンをクリックする度に
「hide」がない状態(CSSの110〜117行目)

.dropdown {
  position: absolute;
  top: 27.5vw;
  left: 0;
  width: 100%;
  transition: 0.5s;
  box-shadow: 2.5vw 2.5vw 2.5vw 0 rgba(102,102,102,0.5);
}

「hide」がある状態(124〜127行目)

.dropdown.hide {
  transform: translateY(-170%) ;
  transition: 0.4s ease-in;
}

が切り替わって、メニューが出たり隠れたりするっていう仕組みです。

 

④バーガーボタンのアニメーション
自分はこの部分のアニメーションが大好きで、サイトを見るとき真っ先に動きを確認したくなっちゃうんですよね。作り手の表に出ないこだわりが詰まってたりするので、斬新な動きしてるボタンを見るとテンション上がります。
「そんな動きがあったかぁ〜」みたいなボタンに出会いたい。

 

それはさておき、

今回は3本線が一度中央に集まってから回転して「×」マークになる、という動きにしました。
「中央に集まる」と「回転して×になる」の動きを2種類のCSSを用意して切り替えています。
(もっといいやり方があるかも!)

 

まず、jQuery。
5、11、17行目でif文で判定を入れています。
これはバーガーボタンがクリックされた時、今メニューが表示されているのか、隠れているのかを確認しています。

if ( $('.burger-menu-button').hasClass('transform') ) {
  〜
} else {
  〜
}

あまり美しくないんですけど、これはメニューを表示するときは「中央に集まる」→「回転して×になる」の順番、メニューを隠すときは「回転して平行線に戻る」→「中央から上下に別れる」の順番、という形でアニメーションの順番が逆になるので、場合分けしています。

 

メニューを表示する場合は12〜16行目。

$('.burger-menu-button').toggleClass('transform');
setTimeout(function(){
  $('.burger-menu-button').toggleClass('transform2');
  $('.dropdown').toggleClass('hide');
},250);

12行目で「transform」というクラスをつけることで、CSSの61〜67行目にあるスタイルに切り替わり、

.burger-menu-button.transform:before {
  transform: translateY(2vw);
}

.burger-menu-button.transform:after {
  transform: translateY(-2vw);
}

3本線の上下の線が中央の線に集まって重なります。

jQueryの13〜16行目のsetTimeout()は指定時間処理を待つ関数です。
ここでは3本線が中央に集まるアニメーションが終わるのを待っています。

 

続いて、14行目で「transform2」というクラスをつけて、CSSの69〜79行目にあるスタイルに切り替えています。

.burger-menu-button.transform2 {
  transform: rotate(-135deg);
}

.burger-menu-button.transform2:before {
  opacity:0;
}

.burger-menu-button.transform2:after {
  transform: translateY(-2vw) rotate(270deg);
}

「before」(3本線の一番上)を透明(opacity: 0;)にしているのは、×を構成するのは線2本で足りるので、1本消しました。
重ねて回転させても良かったかもしれないんですが、ブラウザによって微妙にズレて見切れたりしたら嫌だったので。
ちなみに本体を透明にしちゃうと、3本まとめて透明になっちゃうので注意です(1回やりましたw)。

 

カッコつけてちょっと多めに回転させていますが、回転量は必要に応じて。
本体を回転させると、before、afterも影響を受けますので、反対方向に回転させるときはそれも考慮した回転量を設定します。
回転軸もズレるのでafterには縦位置も調整入れています。

 

アニメーションのスピード感はtransitionに指定している秒数で調整します。
setTimeout()の時間も合わせて調整する必要があるので忘れずに!

15行目については③で解説しています。

 

jQueryの18〜21行目に書いてあるのは、バーガーボタン横の「MENU」という文言の操作です。
メニューを表示させると「CLOSE」という文言に変わるようにしています。

メニューを隠すときはこの逆の動きをしているだけですので、解説は割愛します。

 

念のため、一連の動きをもう一度解説付きで載せておきます。

// バーガーメニューをクリックしたらメニュー表示・非表示を切り替え
$('.burger-menu').on('click', function(){
    if ( $('.burger-menu-button').hasClass('transform') ) { // すでにメニューが表示されていたら
        $('.burger-menu-button').toggleClass('transform2'); // まず回転して平行に戻し
        setTimeout(function(){ // 回転が終わるまで待ってから
            $('.burger-menu-button').toggleClass('transform'); // 3本線を元の位置に戻す
            $('.dropdown').toggleClass('hide'); // メニューをしまう
        },250);
    } else { // まだメニューが表示されていなかったら
        $('.burger-menu-button').toggleClass('transform'); // まず3本線を中央に集めて
        setTimeout(function(){ // 3本線が中央に集まるのを待ち、
            $('.burger-menu-button').toggleClass('transform2'); // 回転させて×マークに変形
            $('.dropdown').toggleClass('hide'); // メニューを表示
        },250);
    }
    setTimeout(function(){ // 変形が終わるのを待ってから
        $('.burger-menu-text').toggleClass('show'); // MENUの文字の表示・非表示を切り替え
        $('.burger-menu-text-close').toggleClass('show'); // CLOSEの文字の表示・非表示を切り替え
    },250);
})

 

 

⑤メニュー外の領域をクリック(タップ)したらメニューを閉じる
細かいんですが、個人的にはサイトを見るときに絶対あって欲しいと思う機能です。
モーダルウィンドウなんかでもそうですね。
作る側としては面倒な機能だと思うんですけど、ぜひ入れて欲しいので、推しておきます。

 

jQueryの25〜37行目がそれに当たります。

25行目でページのどこかがクリックまたはタップされたことを拾っています。

$(document).on('click touchend', function(event) {

26行目で「クリックまたはタップされた領域がメニュー以外の部分だったら」という条件が入っています。

if (!$(event.target).closest('.burger-menu').length) {

あとの中身はバーガーボタンを押した時と基本は変わりません。
違うのはtoggleClass()ではなく、addClass()、removeClass()を使っているという点です。

この場合は「メニューを消す」という動作一択なので、「クラスがなければ追加、あれば削除」の動作をするtoggleClass()ではマッチしないことに注意が必要です。

 

バーガーメニューはカスタマイズの宝庫なので、色々試してみると面白いと思います!

シェアする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする