【CSS/JavaScript】ハンバーガーメニュー自作の手順

【Rails】プログラミング初心者の勉強ブログ #61

ハンバーガーメニューを自作したい。Bootstrapやプラグインではなく、CSSとJSを使い、オリジナルハンバーガーメニューを作るためには、どのタイミングで、どのようなコードが必要になるかを実在サイトをもとに考察しました。

 

目次

[toc]

 

はじめに

今回のハンバーガーメニュー考察は、実在するサイトにお邪魔して、ディベロッパーツールでコードを確認しながら仕組みを理解していくことに努めております。

参考サイト

シザーケース専門店 sacra HP

[blogcard url=”https://sacra-jp.com/”]

 

「実際のメニューの画像」

 

  1. バーガーメニューアイコンをクリック
  2. メニューが表示される
  3. 閉じるボタンでもとの画面に戻る

 

こちらのHPのハンバーガーメニューを参考に、どのような仕組みで上のメニューがコーディングされているかを考察します。

 

ハンバーガーメニューの仕組み

まず、一連のメニュー表示の流れの、どの要素にCSSとJavaScriptが使用されているかをまとめます。CSS使用部分とJS使用部分を一旦整理して考えていきます。

 

JavaScriptの使用箇所

今回のメニューにおいて、JSを使用する点は、大まかに以下の3つでした。

①、バーガーメニューアイコンのクリック時アクション設定

まず、最初の「三」の字のアイコンがクリックされた時のアクションを定義する必要があります。このクリック時のアクションに、「要素にクラスを追加する関数」を定義することで、追加で付与されたクラスに当てた、もともとコーディングしておいたCSSが作用し、アニメーションが起動する流れです。

 

②、①のクリック時のタイミングとずらしてクラスを付与する設定

①のアクション設定は、別途関数を定義をしない限り、クリック時と同タイミングで、設定した全てのアクションが行われることになります。しかし、今回のメニューは、最初のクリックで、背景がグレーからピンクに変わり、その数秒後に白い文字が表示されております。

※クリックタイミングと、白い文字表示タイミングがずれてます。このような「アクションのタイミング」の設定は、JSの「setTimeout関数」で設定を行うことができます。

 

③、「×」印の閉じるボタンのクリック時アクション設定

こちらもクリック時アクションをJSで定義し、①で設定した際に付与したクラスを取り払うことで、もとの状態に戻すと言った流れになります。あらかじめ設定したCSSのクラスを付けたり外したりすることで、表示の変化を生み出すイメージです。

 

実際のコーディング

nav.html(抜粋)

<body>
  //表示されるメニュー中身
  <div class="nav-sp">
    #省略

   //メニュー背景3分割用listタグ
   <ul class="bg-back">
    <li></li>
    <li></li>
    <li></li>
   </ul>
  </div>

  //閉じるボタン(×印)
  <div class="icon-close">
    <div class="icon-close1"></div>
    <div class="icon-close2"></div>
  </div>

  //バーガーメニューアイコン(棒3つ)
  <div class="burger-nav index-burger">
    <div class="icon-menu"></div>
  </div>

 //最後にnav.jsを読み込ませる。(位置が大事)
  <script src="nav.js"></script>

</body>

 

nav.js

$('.burger-nav').click(function() {
    //メニューをフェードイン
    $('.nav-sp').fadeIn(0);

    //①openクラスを追加
    $(this).addClass('open');
    $('.nav-sp').addClass('open');

    //②③setTimeoutでタイマー機能設定、fade-inクラスを遅らせて追加・削除
    setTimeout(function() {
        $('.nav-sp').removeClass('close');
    }, 0);
    setTimeout(function() {
        $('.nav-sp.open .nav li,.icon-close').fadeIn(0);
        $('.nav-sp .nav,.sacra-logo-sp,.nav-sns-sp,.icon-close,.nav-sublink-sp').addClass('fade-in');
    }, 600); 

});

※openとcloseクラスにアニメーション設定がコーディングされてます。詳細は一番下のcssのコードで確認ください。

※「.nav、.sacra-logo-sp、.nav-sns-sp、.icon-close、.nav-sublink-sp」の各クラスは、メニュー内のアイコンやリンク、文字の要素のクラスです。

 

 

CSSの使用箇所

上に書いたJS使用箇所以外は、全てCSSの設定です。アニメーションは全てCSSです。このメニューバーJSのコードよりもCSSのコードの方が、複雑に作り込まれておりました。今回は特に特徴的であった2つのCSSアニメーション2つを取り上げてまとめます。

 

①、メニュー背景を3つに分け、白とピンクの背景色を段階的に表示する設定

この背景が三段階で移動して変わるアニメーション、最初見たとき仕組みが全く想像できなかったのですが、コードを確認すると、メニューの大枠のdiv内にliタグで3つの要素を作成し、それぞれにCSSアニメーションを適用することで作られておりました。

面白いのはliタグ1つにつき、before(白)とafter(ピンク)で2つの擬似要素を作り、左右から表示させていたことです。擬似要素アニメーションの使い方はめちゃめちゃ色々あるんだなと思いました。

 

②、「×」印のアニメーション設定

この閉じるボタンのバツ印も、擬似要素にアニメーションをかけることで作られております。正直、細かい部分まで仕組みを把握することはできておりませんが、対応するコードを以下に載せます。

 

実際のコーディング(まとめ)

nav.html

<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="nav.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<body>
  <!-- ハンバーガーメニュー中身 -->
  <div class="nav-sp">
  <a href="#" class="vm sacra-logo-sp">sacra</a>
  <ul class="nav">
      <li>
          <a href="#" class="vm nav-home">
              <span class="f">H</span>
              <span class="s">O</span>
              <span class="f">M</span>
              <span class="s">E</span>
          </a>
      </li>
      <li>
          <a href="#" class="vm nav-scissorscase">
              <span class="f">S</span>
              <span class="s">C</span>
              <span class="f">I</span>
              <span class="s">S</span>
              <span class="f">S</span>
              <span class="s">O</span>
              <span class="f">R</span>
              <span class="s">S</span>
              <span class="f">C</span>
              <span class="s">A</span>
              <span class="f">S</span>
              <span class="s">E</span>
          </a>
      </li>
      <li>
          <a href="#" class="vm nav-floristcase">
              <span class="f">F</span>
              <span class="s">L</span>
              <span class="f">O</span>
              <span class="s">R</span>
              <span class="f">I</span>
              <span class="s">S</span>
              <span class="f">T</span>
              <span class="s">C</span>
              <span class="f">A</span>
              <span class="s">S</span>
              <span class="f">E</span>
          </a>
      </li>
      <li>
          <a href="#" class="vm nav-about">
              <span class="f">A</span>
              <span class="s">B</span>
              <span class="f">O</span>
              <span class="s">U</span>
              <span class="f">T</span>
          </a>
      </li>
      <li>
          <a href="#" class="vm nav-shop">
              <span class="f">S</span>
              <span class="s">H</span>
              <span class="f">O</span>
              <span class="s">P</span>
              <span class="f">L</span>
              <span class="s">I</span>
              <span class="f">S</span>
              <span class="f">T</span>
          </a>
      </li>
      <li>
          <a href="#" class="vm nav-support is-current">
              <span class="f">S</span>
              <span class="s">U</span>
              <span class="f">P</span>
              <span class="s">P</span>
              <span class="f">O</span>
              <span class="s">R</span>
              <span class="f">T</span>
          </a>
      </li>
      <li>
          <a href="#" class="nav-online is-current" target="_blank">
              <span class="f">O</span>
              <span class="s">N</span>
              <span class="f">L</span>
              <span class="s">I</span>
              <span class="f">N</span>
              <span class="s">E</span>
              <span class="f">S</span>
              <span class="s">T</span>
              <span class="f">O</span>
              <span class="s">R</span>
              <span class="f">E</span>
          </a>
      </li>
  </ul>
  <!-- .nav -->
  <ul class="nav-sns-sp">
      <li>
          <a href="#" class="instagram" target="_blank">
              <span class="icon-instagram"></span>
          </a>
      </li>
      <li>
          <a href="#" class="facebook" target="_blank">
              <span class="icon-facebook"></span>
          </a>
      </li>
  </ul>
  <ul class="nav-sublink-sp">
      <li>
          <a class="vm" href="#">COMPANY</a>
      </li>
      <li>
          <a class="vm" href="#">PRIVACY POLICY</a>
      </li>
      <li>
          <a class="vm" href="#">CONTACT</a>
      </li>
      <li class="copyright">Copyright sacra All rights reserved.</li>
  </ul>
  <ul class="bg-back">
      <li></li>
      <li></li>
      <li></li>
  </ul>
  </div>
  <!-- / .nav-sp -->
  <div class="burger-nav burger-main">
    <div class="icon-menu"></div>
  </div>
  <!-- ×ボタン -->
  <div class="icon-close">
    <div class="icon-close1"></div>
    <div class="icon-close2"></div>
  </div>
  <!-- 棒三本 -->
  <div class="burger-nav index-burger">
    <div class="icon-menu"></div>
  </div>
  <script src="nav.js"></script>
</body>

 

nav.css(抜粋)

//メニュー背景3分割表示
.nav-sp{
	display:none;
	top:0%;
	left:0%;
	width:100%;
	height:100%;
	position:fixed;
	z-index:10000;
	-webkit-transition: all ease 0s;
  transition: all ease 0s;
}
.nav-sp .bg-back li:after{
	content:"";
	opacity:1;
	width:100%;
	height:34%;
	right:0%;
	transform:translate(100%,0);
	position:absolute;
	background: rgba(220,111,100,1);
	z-index:1;
}
.nav-sp .bg-back li:before{
	content:"";
	opacity:1;
	width:100%;
	height:34%;
	left:0;
	transform:translate(-100%,0);
	position:absolute;
	z-index:-1;
	background: rgba(255,255,255,1);
}
.nav-sp .bg-back li:nth-of-type(1):after{
	-webkit-transition: all cubic-bezier(.8,1,.32,1) 0.6s;
  transition: all cubic-bezier(.2,.4,1) 0.6s;
	top:0%;
}
.nav-sp .bg-back li:nth-of-type(2):after{
	-webkit-transition: all cubic-bezier(.8,1,.32,1) 0.7s;
  transition: all cubic-bezier(.2,.4,1) 0.7s;
	top:33.3333%;
}
.nav-sp .bg-back li:nth-of-type(3):after{
	-webkit-transition: all cubic-bezier(.8,1,.32,1) 0.8s;
  transition: all cubic-bezier(.2,.4,1) 0.8s;
	bottom:0%;
}
.nav-sp .bg-back li:nth-of-type(1):before{
	-webkit-transition: all cubic-bezier(.8,1,.32,1) 0.6s;
  transition: all cubic-bezier(.2,.4,1) 0.6s;
	top:0%;
}
.nav-sp .bg-back li:nth-of-type(2):before{
	-webkit-transition: all cubic-bezier(.8,1,.32,1) 0.7s;
  transition: all cubic-bezier(.2,.4,1) 0.7s;
	top:33.3333%;
}
.nav-sp .bg-back li:nth-of-type(3):before{
	-webkit-transition: all cubic-bezier(.8,1,.32,1) 0.8s;
  transition: all cubic-bezier(.2,.4,1) 0.8s;
	bottom:0%;
}
.nav-sp.open .bg-back li:nth-of-type(1):after,
.nav-sp.open .bg-back li:nth-of-type(2):after,
.nav-sp.open .bg-back li:nth-of-type(3):after,
.nav-sp.open .bg-back li:nth-of-type(1):before,
.nav-sp.open .bg-back li:nth-of-type(2):before,
.nav-sp.open .bg-back li:nth-of-type(3):before{
	transform:translate(0,0);
}



//閉じるボタン設定
.icon-close{
	display:none;
	width:50px;
	height:50px;
	top: 20px;
  right: 35px;
	position:fixed;
	z-index:10001;
	cursor:pointer;
	transition: transform .6s cubic-bezier(.23,1,.32,1);
}

//閉じるボタンバツ印設定
.icon-close1 {
	transition: transform .6s cubic-bezier(.23,1,.32,1),opacity .2s;
  position: absolute;
  height: 1px;
  width: 30px;
  top: 25px;
  background-color: #333;
  left: 26px;
	opacity: 0;
	transform: translateX(-50%) translateY(-50%) rotate(45deg) translateZ(0);
}
.icon-close1:before {
 	-webkit-transition-duration: 0.7s;
	transition-duration: 0.7s;
	transform-origin: 0 0;
  transform: scaleX(.3) translateX(-130%) translateZ(0);
	position: absolute;
	width: 16px;
	height: 1px;
	background-color: #fefefe;
	content: "";
	top: 0px;
	left: -1px;
}
.icon-close1:after {
	-webkit-transition-duration: 0.7s;
  transition-duration: 0.7s;
	transform-origin: 100% 0;
  transform: scaleX(.3) translateX(130%) translateZ(0);
  position: absolute;
  width: 16px;
  height: 1px;
  background-color: #fefefe;
  content: "";
  top: 0;
  left: 15px;
}

.icon-close2 {
	transition: transform .6s cubic-bezier(.23,1,.32,1),opacity .2s;
  position: absolute;
  height: 1px;
  width: 30px;
  top: 25px;
  background-color: #fefefe;
  left: 26px;
	opacity: 0;
	transform: translateX(-50%) translateY(-50%) rotate(-45deg) translateZ(0);
}
.icon-close2:before {
 	-webkit-transition-duration: 0.7s;
	transition-duration: 0.7s;
	transform-origin: 0 0;
  transform: scaleX(.3) translateX(-130%) translateZ(0);
	position: absolute;
	width: 16px;
	height: 1px;
	background-color: #eee;
	content: "";
	top: 0px;
	left: -1px;
}
.icon-close2:after {
	-webkit-transition-duration: 0.7s;
  transition-duration: 0.7s;
	transform-origin: 100% 0;
  transform: scaleX(.3) translateX(130%) translateZ(0);
  position: absolute;
  width: 16px;
  height: 1px;
  background-color: #eee;
  content: "";
  top: 0;
  left: 15px;
}

.icon-close.fade-in .icon-close1,
.icon-close.fade-in .icon-close2 {
	opacity: 1;
  transition: transform .6s cubic-bezier(.23,1,.32,1);
  background: transparent;
}
.icon-close.fade-in .icon-close1:before,
.icon-close.fade-in .icon-close1:after,
.icon-close.fade-in .icon-close2:before,
.icon-close.fade-in .icon-close2:after {
	transform: scaleX(1) translateX(0) translateZ(0);
  transition: transform .6s cubic-bezier(.23,1,.32,1),opacity .2s;
}
.icon-close.fade-in:hover{
	transform:rotate(-90deg);
}
.icon-close.fade-in:hover .icon-close1:before,
.icon-close.fade-in:hover .icon-close2:before{
	transform-origin: 0 0;
  transform: scaleX(.7) translateX(-20%) translateZ(0);
}
.icon-close.fade-in:hover .icon-close1:after,
.icon-close.fade-in:hover .icon-close2:after {
	transform-origin: 100% 0;
  transform: scaleX(.7) translateX(20%) translateZ(0);
}

.burger-nav:hover,
.icon-close:hover {
  cursor: pointer;
}

 

nav.js

/*バーガーメニュー*/
$('.burger-nav').click(function() {
    $('.nav-sp').fadeIn(0);
    $(this).addClass('open');
    $('.nav-sp').addClass('open');
    setTimeout(function() {
        $('.nav-sp').removeClass('close');
    }, 0);
    // setTimeoutでタイマー機能をつけ、「fade-in」クラスを「open」クラスに遅らせて付与している
    setTimeout(function() {
        $('.nav-sp.open .nav li,.icon-close').fadeIn(0);
        $('.nav-sp .nav,.sacra-logo-sp,.nav-sns-sp,.icon-close,.nav-sublink-sp').addClass('fade-in');
    }, 600); 

    // スクロールを無効にする
    //SP用
    $(window).on('touchmove.noScroll', function(e) {
        e.preventDefault();
    });
    //PC用
    var scroll_event = 'onwheel'in document ? 'wheel' : 'onmousewheel'in document ? 'mousewheel' : 'DOMMouseScroll';
    $(document).on(scroll_event, function(e) {
        e.preventDefault();
    });

});

/*closeボタン*/
$('.icon-close').click(function() {
    $('.nav-sp .nav,.sacra-logo-sp,.nav-sns-sp,.icon-close,.nav-sublink-sp').removeClass('fade-in');
    setTimeout(function() {
        $('.nav-sp').addClass('close');
        $('.burger-nav').removeClass('open');
        $('.nav-sp').removeClass('open');
    }, 600);
    setTimeout(function() {
        $('.nav-sp,.icon-close').fadeOut();
    }, 1200);
    // スクロール無効を解除する
    //PC用
    var scroll_event = 'onwheel'in document ? 'wheel' : 'onmousewheel'in document ? 'mousewheel' : 'DOMMouseScroll';
    $(document).off(scroll_event);
    //SP用
    $(window).off('.noScroll');
});

 

まとめ

今回はバーガーナビの表示の仕組みについてでした。今回のようなナビゲーション表示の場合、複雑なのはJavaScriptよりもCSSです。CSSの理解は正直追っついていませんが、一回一回ディベロッパーツールでコードを確認し仕組みを考察してみると、色々なサイトのバーガーメニューを見た際に、どのように作られているかのイメージが湧くようになります。

以上ありがとうございました。

返信を残す

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

CAPTCHA