Worse is better.😀

レスポンシブ対応!世界一簡単なハンバーガーメニューの実装法(コピペOK)

CSS3

こんにちは、北陸のwebコーダーdaimaです。
本日は、ナビゲーションをコンパクトに纏められる
おしゃれなハンバーガーメニューの実装方法をご紹介します。
まずは下記のデモページをご覧ください。

最終更新2020/07/04 : ページ内リンクのクリックした際に自動でメニューを閉じた上で目的地点までスムーズスクロールを行う記述を追加しました。

今回はこのように、至ってシンプルな
ハンバーガーメニューを作成します。
動作確認済ブラウザはChrome、IE、FireFox、safariの
最新バージョン(記事執筆時点)です。

ソースコードと解説

<div class="header">
  
  <div class="el_humburger">
    <span class="top"></span>
    <span class="middle"></span>
    <span class="bottom"></span>
  </div>
    
  <div id="uq_spNavi" class="uq_spNavi">
    <div class="uq_spNavi_screen">
      <nav class="navigation">
        <div class="navigation_item"><a href ="https://spreadsheep.net/post-240/">記事に戻る</a></div>
        <div class="navigation_item"><a href ="#inner_link">ページ内リンク</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
        <div class="navigation_item"><a href ="#">CONTENT</a></div>
      </nav>
    </div>
  </div>
</div>

<div class="wrap">

  <div class="content">
    I LOVE HUMBURGUR MENU
  </div>

  <div id="inner_link" class="content2">
    INNER LINK
  </div>

</div>

HTMLソースです。
ハンバーガーボタンとナビゲーションの
マークアップを行っています。

/*基本レイアウトの調整*/
body {
  margin: 0;
}

.wrap {
  padding: 60px 0 0 0;
  background-color: #f8e0f7;
}

.content {
  text-align: center;
  font-size: 22px;
  color: #bf86ce;
  height: 2000px;
  padding: 60px;
}
.content2{
  font-size: 22px;
  color: #bf86ce;
  padding-top: 100px;
  padding-bottom:1000px;
  text-align: center;
}

/*ハンバーガーボタン*/
.header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 60px;
  background-color: #be9dc9;
}

.el_humburger {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 26px;
  height: auto;
  padding-top: 1px;
  box-sizing: border-box;
  z-index: 10000;
  transition: all 0.2s ease-in-out;
  cursor: pointer;
  pointer-events: auto;
}

.el_humburger > span {
  display: block;
  width: 100%;
  margin: 0 auto 6px;
  height: 3px;
  background: #000;
  transition: all 0.2s ease-in-out;
}
.el_humburger > span:last-child {
  margin-bottom: 0;
}
.js_humburgerOpen .el_humburger > span {
  background: #000;
}

.js_humburgerOpen .el_humburger > span.top {
  transform: translateY(9px) rotate(-45deg);
}

.js_humburgerOpen .el_humburger > span.middle {
  opacity: 0;
}

.js_humburgerOpen .el_humburger > span.bottom {
  transform: translateY(-9px) rotate(45deg);
}

.el_humburgerButton.el_humburgerButton__close {
  top: 2%;
  right: 2%;
}

.el_humburgerButton__close > span {
  display: block;
  width: 35px;
  margin: 0 auto;
  height: 4px;
  background: #fff;
}

.el_humburgerButton__close > span.el_humburgerLineTop {
  transform: translateY(5px) rotate(-45deg);
}

.el_humburgerButton__close > span.el_humburgerLineBottom {
  transform: translateY(-6px) rotate(45deg);
}

/*ナビゲーション*/
.uq_spNavi {
  display: none;
}
.uq_spNavi.js_appear {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  display: block;
  z-index: 9999;
}

.uq_spNavi_screen {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: rgba(255, 255, 255, 0.96);
  z-index: 0;
  margin-top: 0px;
  padding-top: 0px;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.navigation {
  padding: 80px 0 0 0;
  text-align: center;
}

.navigation_item {
  font-ize: 18px;
  margin-bottom: 20px;
}

.navigation_item > a {
  color: #000;
  text-decoration: none;
}

.js_fixed {
  position: fixed;
  width: 100%;
  height: 100%;
}

CSSソース。
ハンバーガーボタンの動作と
ナビゲーション表示時の
レイアウト指定を行っています。

ここでのミソは、
.navigation_screenに記載されている
-webkit-overflow-scrolling: touch;というプロパティ。
これを指定しておくと、
スマホでナビゲーション内部を
スワイプしたときの動作が滑らかになります。

  // スクロール可能な要素を判別する関数
function getFirstScrollable(selector){
  var $scrollable;

  $(selector).each(function(){
    var $this = $(this);
    if( $this.scrollTop() > 0 ){
      $scrollable = $this;
      return false;
    }else{
      $this.scrollTop(1);
      if( $this.scrollTop() > 0 ){
        $scrollable = $this;
        return false;
      }
      $this.scrollTop(0);
    }
  });


  return $scrollable;
}

//スムーズスクロール処理を行う関数
function smoozScroll($target){

  if($('body.js_humburgerOpen').length){
    spNavInOut.switch();
  }

  //変数のセッティング
  var $win = $(window),
      $doc = $(document),
      $scrollElement = getFirstScrollable("html,body"),
      mousewheel = "onwheel" in document ? "wheel" : "onmousewheel" in document ? "mousewheel" : "DOMMouseScroll";

    var top;

    // 現在のウィンドウ幅を取得
    var w = $(window).width();

    // $targetが空の場合はキャンセル
    if( $target.size() < 1 ) return false;

    // スクロール先の位置を調整
    top = $target.offset().top;
    top = Math.min(top, $doc.height() - $win.height());

    // スクロール中は手動スクロールをキャンセルする
    $doc.on(mousewheel, function(e){ e.preventDefault(); });

    // 移動先へアニメーションする
    $scrollElement.stop().animate({scrollTop: top - 0}, 600, "linear", function(){
      $doc.off(mousewheel);
    });
};

  $(function(){

    var $win = $(window),
        $doc = $(document);

      //アンカーリンクをクリックした時にアクションを起こす処理
      $doc.on("click", "a[href^=\\#]", function(e){
        /*if($(this).data('option')){
          if($(this).data('option') === "close_selector"){
            $('.js_pullDownParent').removeClass('js_fire');
          }
        }*/
        var $target = $(this.hash),
            top;

        smoozScroll($target);

        return false;
      });
  });


//ハンバーガーメニュー
$(function(){
  $('.el_humburger').on('click',function(){
    spNavInout();
  });
  $('.navigation_item a').on('click',function(){
    spNavInout();
  });
});

//spナビ開く処理

function spNavIn(){
  $('body').removeClass('js_humburgerClose');
  $('body').addClass('js_humburgerOpen');
  $(".uq_spNavi").addClass("js_appear");
  $(".uq_spNavi").css({opacity:0});
  $(".uq_spNavi").animate({
    opacity: 1
  },200);
  scrollBlocker(true);
}

//spナビ閉じる処理
function spNavOut(){
  $(".uq_spNavi").animate({
    opacity: 0
  },200)
  $('body').removeClass('js_humburgerOpen');
  $('body').addClass('js_humburgerClose');
  setTimeout(function(){
    $(".uq_spNavi").removeClass("js_appear");
  },200);
  scrollBlocker(false);
}

//spナビ開閉処理
function spNavInout(){
  if($('body.spNavFreez').length){
    return false;
  }
  if($('body').hasClass('js_humburgerOpen')){
   spNavOut();
  } else {
   spNavIn();
  }
}

//ナビ向けスクロール無効化処理

var scrollBlockerFlag;

function scrollBlocker(flag){
  if(flag){
    scrollpos = $(window).scrollTop();
    $('body').addClass('js_fixed').css({'top': -scrollpos});
    scrollBlockerFlag = true;
  } else {
    $('body').removeClass('js_fixed').css({'top': 0});
    window.scrollTo( 0 , scrollpos );
    scrollBlockerFlag = false;
  }
}

そして最後がjavascipt(jQuery)ソース。
ここでやっていることは大きく分けて次の3つです。

1.ハンバーガーメニュー内のページ内リンクをクリックした場合にスムーズスクロールとメニューを自動で閉じる処理を行う(1~77行目)

2.bodyにナビゲーション判別用のクラス「js_humburgerOpen」があるか判定し、
なければクラスの追加とナビゲーションの表示処理、
あればクラスの削除とナビゲーションの非表示処理を行う。(80~126行目)

3.自作関数scrollBlockerで、
ナビゲーションが開いているときに、
body及びhtmlがスクロールしないように固定する。(128~142行目)

特に3の部分で少し凝った処理をしていて、
まずナビオープン時のy位置を取得し、
次にbodyにクラス「js_fixed」を付与して
bodyのpositionを一時的にfixedに変更しています。

そして最後にcssのtopでbodyのy位置を
ナビオープン時のスクロール量分ずらし、
見た目上の表示位置を合わせることによって
スクロールの固定を実現しているのです。

この処理上、ナビオープン時の
yスクロール量は必ず0になります。
ですので、当ナビを導入して
万が一他の処理に不具合が起きた場合は
まずこの点を疑ってみてください。

さいごに

ハンバーガーメニューの実装処理、
上手くいきましたでしょうか。

ハンバーガーメニューはおしゃれで大変便利ですが、
ユーザビリティの観点から見ると、
年配の方には一見してメニューだと
分かり辛い
という指摘もしばしば聞かれます。

ですので、年配のユーザーが多い
サイトに導入する場合は
ハンバーガーの直下に「メニュー」の
表記を足す
などのひと工夫を行うと良いでしょう。

今回ご紹介したのは、あくまでも
必要最低限の枠組みだけですので、
仕組みが理解出来たらぜひ、
あなただけのオリジナルのメニューに
カスタマイズしてみてください。

それでは!

コメント

  1. 赤堀 竜海 より:

    初めまして!質問がありコメントさせていただきました。

    sp時にハンバーガーメニューを取り入れたいのですが、ハンバーガーメニューをクリックしてもnavigationが表示されません、、、

    もし思い当たる原因などありましたら教えていただけると幸いです。

    よろしくお願いいたします。

    • daima より:

      赤堀様、コメントありがとうございます。
      管理人のdaimaです、お返事遅くなりごめんなさい。

      navigationが表示されないということですが
      原因の特定にはこちらで実際のコードを確認する必要があります。

      ですので、もし差し支えなければ
      コードデータかサイトURLをフォームからお伝えください。

  2. yajio より:

    daimaさん
    navigationを左から右にスライド表示ってできるのでしょうか?
    よろしくお願い申し上げます。

    • daima より:

      yajioさんご訪問ありがとうございます。
      こちら、javasctriptのanimateメソッドで動きをつけていますので
      そちらをcssと合わせて調整すればスライド表示にも変更可能かと思います。

  3. 石川剛 より:

    初めまして、石川と申します。

    こちらのハンバーガーメニューの導入がとても分かりやすく良く使用しています。
    ページ内アンカーリンクの先に閉じるようにすることは出来るのでしょうか?
    jsの知識がなく苦戦しています。

タイトルとURLをコピーしました