[jQuery] プラグインを使わずに横からスライドインするメニューを簡単に作る

スマートフォンやレスポンシブサイトなどでよく見かける、メニューボタンをクリックするとコンテンツを押し出してメニューがスライドインしてくる動きを jQuery と CSS で作る方法です。やってみると意外と簡単なコードで作ることができます。

サンプルデモとダウンロード

◆ 横からスライドインするメニュー demo|memocarilog

このサンプルコードは以下よりダウンロードできます。
◆ SaoriMiyazaki/SlideIn_Menu

HTMLコード

スライドインしてくるメニューとメニューボタンの記述をします。

<!-- スライドメニュー部分-->
<nav id="slide_menu">
	<ul>
		<li><a href="#">menu1</a></li>
		<li><a href="#">menu2</a></li>
		<li><a href="#">menu3</a></li>
		<li><a href="#">menu4</a></li>
		<li><a href="#">menu5</a></li>
    </ul>
</nav>

<!--メニューを出すボタン-->
<button id="button"><i class="fa fa-bars"></i> Menu</button>

CSSコード

動きに必要なところだけ抜き出しました。

まず、body に対して position: relative; を指定し position 位置の起点にします。そして、overflow-x を hidden にして横幅からあふれたものに対してだけ非表示にします。overflow にしてしまうと縦のスクロールバーがでなくなってしまうのでご注意です。

body {
    position: relative;
	left: 0;
	overflow-x: hidden;
}

次に、スライドインするメニューに以下のように指定します。

#slide_menu{
	position: fixed;
	top: 0;
	left: -240px;
	width: 240px;
	height: 100%;
    background: #E87272;
}

position を fixed; にして位置を固定します。left に メニューの横幅のマイナス値を設定し、画面左端よりも左にはみだした位置にし画面から見えないようにします。 あとは、height を 100%; にし画面縦幅いっぱいをメニューのエリアにします。

jQuery コード

jQuery 本体と以下のコードを読み込みます。4行目には、スライドインするメニューのセレクタを指定し、5行目にはクリックするボタンを指定して下さい。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(function(){
var menu = $('#slide_menu'), // スライドインするメニューを指定
	menuBtn = $('#button'), // メニューボタンを指定
	body = $(document.body), 	
    menuWidth = menu.outerWidth();	            
	
	// メニューボタンをクリックした時の動き
    menuBtn.on('click', function(){
    // body に open クラスを付与する
	body.toggleClass('open');
        if(body.hasClass('open')){
        	// open クラスが body についていたらメニューをスライドインする
			body.animate({'left' : menuWidth }, 300);			
			menu.animate({'left' : 0 }, 300);					
		} else {
			// open クラスが body についていなかったらスライドアウトする
			menu.animate({'left' : -menuWidth }, 300);
			body.animate({'left' : 0 }, 300);			
		}		     
    });
});    
</script>

ボタンをクリックする毎に、body 要素に open というクラスが付与と削除を交互に繰り返します。この open クラスが付いている時にメニューを表示し、付いていなかったら非表示にするということを行っています。

クリック時に open クラスが付いていたら、CSS 側で隠していたメニューを画面左端に位置を変更して表示し、open クラスが付いていなかったら、再び画面左端よりも左にメニュー位置を変更し非表示にします。

この位置の移動を animate メソッドでアニメーションにして完成です。

もし、右からスライドインさせたい場合は position 位置を right に変更すればよいだけなのでアレンジも簡単です。

全てのコードは、こちら(HTML/JS)「SlideIn_Menu/index.html at master · SaoriMiyazaki/SlideIn_Menu」とこちら(CSS)「SlideIn_Menu/style.css at master · SaoriMiyazaki/SlideIn_Menu」でご確認頂けます。

メニューをスライドインした時に縦のスクロールが可能なサンプル ※2015/10/17 追記

コメントやお問い合わせなどで聞かれることが多かったので、メニューをスライドインした際に、メニューとコンテンツ部分の縦スクロールが可能なバージョンのサンプルを作成しました。メニューの数が多い場合にメニューが切れることがありません。

ダウンロード

以下より縦スクロール可能なバージョンのサンプルをダウンロードできます。

SaoriMiyazaki/SlideIn_Menu at scroll_container

サンプルデモ

デモは以下です。
横からスライドインするメニュー(スクロール可能版)demo|memocarilog

メニューが開いている時にコンテンツ部分をクリックしても閉じることができるようにする ※2015/5/15 追記

コメントにてご質問頂いたので、以下追記しました。

上記サンプルでは、メニューボタンのみが閉じる動作のトリガーとなっています。これをコンテンツ部分をクリックしても閉じることが可能にします。

HTML コード

まず、HTML のどこかに div.layer を追加します。

<body>
<div class="layer"></div>
<div class="container">
:
略
:

CSS コード

追加した div.layer の width と height を100%にして画面いっぱいの領域に広げ、通常時は display:none にして非表示にしておきます。#slide_menu に z-index: 3; #button に z-index: 2; .layer に z-index: 1;の順に重なる指定をします。

.layer{
    position: fixed;
    top: 0;
    z-index: 1;
    display: none;
    width: 100%;
    height: 100%;
    background-color: transparent;
}
body.open{
    position: fixed;
}

body に open クラスが付与されているとき(メニューオープン時)には、body に position: fixed を指定して固定します。

jQuery コード

jQuery を以下のようにします。

$(function(){
var menu = $('#slide_menu'),
    menuBtn = $('#button'),
    body = $(document.body),
    // .layer もオブジェクト化	
    layer = $('.layer'),
    menuWidth = menu.outerWidth();	            
        
    menuBtn.on('click', function(){
	body.toggleClass('open');
        if(body.hasClass('open')){
            // css で非表示にしていた .layer を表示
            $(".layer").show();
            body.animate({'left' : menuWidth }, 300);
            menu.animate({'left' : 0 }, 300);					
        } else {
            // .layer を非表示
            $(".layer").hide();
            menu.animate({'left' : -menuWidth }, 300);
            body.animate({'left' : 0 }, 300);			
        }		     
    });
    // .layer をクリック時にもメニューを閉じる
    layer.on('click', function(){
            menu.animate({'left' : -menuWidth }, 300);
            body.animate({'left' : 0 }, 300).removeClass('open');
            layer.hide();
    });
});   

メニューをクリックした時に先ほど追加した .layer を表示させます。そして .layer をクリック時にもメニューを閉じるようクリックイベントを追加し、メニューを閉じると同時に .layer を再び非表示にします。

Comments 29

  • 簡単に実装できました。ありがとうございます。
    一点だけ、スマホで動作確認するとメニュー部分とボディが動いてしまいます。
    例えば、FACEBOOKのメニューのような横は固定されて縦スクロールだけ動くようにする事は可能でしょうか?

    • sharon apple さま

      ご参考ありがとうございます。
      もし、body 部分を同時にスライドさせたくないということなら、jQuery コード内にある body.animate({ … という2行を削除して頂ければメニュー部分だけが橫スライドするようになります。

  • ご教授いただいたやり方を試してみましたがbodyがスライドしないでメニューのみがスライドしてbodyと重なってしまいました。ちょっとイメージしている動きとは違いました。
    本当にFACEBOOKまんまの動きなんですが・・・
    bodyとメニューが一緒にスライドして固定される感じです。でも縦スクロールだけは出来るみたいな・・・

    作者のソースに

    body.animate({‘left’ : menuWidth }, 300);
    menu.animate({‘left’ : 0 }, 300);
    body.addClass(‘bfixed’); ←追加

    .fixed{position:fixed;top:0;left:240px;}

    このように追加して縦スクロールは出来ませんが何とか近い動きになりました。

    ありがとうございます。

    今後もいろいろと参考にさせていただきます。

  • この記事のおかげで、横からスツと出てくるスライドメニューを実装することができ、大変ありがとうございました。

    メニュー部分がスクロールできないことで難航していましたが、
    「 menu.animate({‘left’ : 0 }, 300); の行をを menu.animate({‘left’ : -240 }, 300); に変更し、#slide_menu の CSS の position を absolute へ変更、height を auto へ変更」

    すると、コメント欄の助言で無事スクロールできるようになりました。

    できれば、body部分は動かさずに、スライドメニュー部分だけスクロールしたいのですが、そのようにもできるのでしょうか?

    できるのであれば、ご教示くださるとありがたいです。

    • winballot さま

      ご参考ありがとうございます。
      仰っている動作も実装可能ではないかと思います。

      実際にコードを書いて動作を確認してみないとわからないところがございますので、
      時間がある時に、そういった動きのサンプルも追記できたらよいなと思います。

  • スマホサイトでjQueryMobileのスワイプメニューが使用できないサイト環境で、困っていたところに、こちらを見つけて活用させていただきました。ありがとうございますm(__)m

    1点だけ、メニューをスクロールさせるために、上記の変更をしたところ、iPhone Safariで、メニューが非表示にならない、という現象がありました。
    なかなか解決策がみつからなかったため、どなたかの参考になればと思い、コメントさせていただきます。

    cssに下記の2行を追加で、バッチリでした。

    html{overflow-x: hidden;position: relative;}
    html body.open{overflow-x: visible;}

    • izanami さま

      ご参考ありがとうございます。
      また、CSS のご指摘もありがとうございました!

  • ありがとうございます。上手く実装できたのですが…

    PCだと何もないのですが、スマホ(iphone)だとボタン押して動作後戻ると、コンテンツの文字が大きくなってしまいました。(font-sizeの指定が無視されました)

    おそらく、左のメニューが出た部分がそのまま範囲として認識されてしまっているからかと、思いますが何か良い解決策とかありますでしょうか?

    • 追加ですが…原因は

      body.open{
      position: fixed;
      }

      でした。これが原因でテキストの文字サイズが無視されました。何か良い方法ありますか?

      • kei さま

        全てのコードをみていないのでなんとも言えませんが、position: fixed; が原因でテキストの文字サイズへ影響を与えているとは考えにくい気がします…、body.open に何かフォントサイズの指定を入れているのでしょうか?それならば、通常の body に通常時のフォントサイズを入れておけばよさそうかなと思いますがいかがでしょうか。

  • こんにちは、アコーディオンメニューで悩んでいるときに、このページはとても参考になり、助かりました。
    初心者なので、自分で考えて実装することが出来ないので質問お願いしても宜しいでしょうか?

    アコーディオンメニューが開いている時にメニューに閉じるボタンを付けたいのですが
    どうしたいいかわかりません。

    http://eduardomb.github.io/jquery-panelslider/
    上記のページの「Open right panel」にしたときの「Close」ボタンをアコーディオンメニューの頭につけたいのです。

    急ぎではないので、お手すきの時にご教授頂けますでしょうか?

  • いつも参考にさせていただいております。
    ありがとうございます。

    ただの任意のテキストをクリックすればメニューが出るようにしたいのですが、
    どうすればよろしいのでしょうか??

    aの中に記述するだけで機能するように等はできないものでしょうか。

    • <button id="button"><i class="fa fa-bars"></i> Menu</button>

      の部分を a タグに変更して id を button としていただければ大丈夫だと思います。

  • 昨日こちらのサイトにたどり着きました。
    他のサイトのdrawer-menu(ハンバガーメニュー)よりもわかりやすく参考になりました。
    これからいつになるかわかりませんが、可変をして使わせていただきたいと思います。
    これからも貴サイトを参考にさせていただきます。
    ありがとうございました。

    64歳の老人より

    • kouya さま
      コメントありがとうございます!励みになります。記事がご参考になれば幸いです。

  • ありがとうございます。
    このサイトのお陰でスライドメニューが作れました。

    ただひとつ質問なのですが、
    今ランディングページをつくっているのですがハッシュリンク#リンクが使えません。

    • ヤマっち さま
      その要素へ #button という ID を使用されていませんか?
      もしくはその他のクリックイベントが発生するスクリプトと干渉していませんか?

  • 先日こちらの記事を拝見させて頂き、おかげでスライドメニューの実装が出来ました。ありがとうございます。

    ところで、スクロール時に画面上部にメニューを固定表示するべく、
    #slide_menuの親要素にposition:fixed;を指定すると、
    スクロール発生時にスライドメニューの表示が壊れてしまいます。

    色々と試しているのですがまだ正解に辿り着けなく難儀しております。
    もしよろしければ何かアドバイス頂けましたら幸いです。

    • ご参考いただきありがとうございます。
      返信が遅くなり申し訳ありません。

      メニュー自体は fixed されているので、ボタンの方のみ fixed してみるのはどうでしょうか?

  • こんにちは。
    プラグインではうまくいかないものが多い中、こちらの記事を参考にメニュー実装できました。
    わかりやすい記事をありがとうございます。

    こちらをアレンジして、
    ・メニューボタンをfixedしてスクロールすると同じ位置で追随(CSSで実装しました)
    ・ボタンにもアニメーションを付け、メニューがスライドイン・アウトするのに合わせて同じ幅だけスライドイン・アウトさせる(ボディと同じ動きをスクリプトに追記しました)
    ・最初はボタンを隠し、トップから150ピクセルスクロールした時点でフェイドイン、150ピクセル以下になればフェイドアウト(スクリプト追記で実装しました)
    としました。

    これだけですと、メニュー本体が表示されたままページトップに戻った場合、
    ボタンだけが消えてメニューが残ったままになってしまうので、
    トップから150ピクセル以下になった場合は
    ・ボタンがフェイドアウトすると同時にメニューがスライドアウト
    ・再度スクロールしてトップから150ピクセル以上になった場合はボタンのみフェイドイン
    という動きにしたいのですが、なかなか思い通りの動きになりません。

    アレンジに関しては初心者で、わからないなりに調べたり色々試したりもしたのですが未だ未解決です。

    お手数をおかけして申し訳ないのですが、何かヒントになるようなご意見をいただければ幸いです。

  • こんにちは。
    昨日質問させていただいた者です。

    以下のコードで解決できました。

    var menu = $(‘#slide_menu’), // スライドインするメニューを指定
    menuBtn = $(‘#button’), // メニューボタンを指定
    body = $(document.body),
    menuWidth = menu.outerWidth();

    // メニューボタンをクリックした時の動き
    menuBtn.on(‘click’, function(){
    // body に open クラスを付与する
    body.toggleClass(‘open’);
    if(body.hasClass(‘open’)){
    // open クラスが body についていたらメニューをスライドインする
    body.animate({‘left’ : menuWidth }, 300);
    menu.animate({‘left’ : 0 }, 300);
    menuBtn.animate({‘left’ : menuWidth }, 300);
    } else {
    // open クラスが body についていなかったらスライドアウトする
    menu.animate({‘left’ : -menuWidth }, 300);
    body.animate({‘left’ : 0 }, 300);
    menuBtn.animate({‘left’ : 0 }, 300);
    }
    });

    menuBtn.hide();
    $(window).on(‘scroll’, function () {
    if( $(this).scrollTop() > 200 ) {
    menuBtn.stop(true,true).fadeIn(1500);
    } else {
    // bodyにopenがついていたら
    if(body.hasClass(‘open’)){
    menu.animate({‘left’ : -menuWidth }, 300);
    body.animate({‘left’ : 0 }, 300).removeClass(‘open’);
    menuBtn.animate({‘left’ : 0 }, 300);
    }
    menuBtn.stop(true,true).fadeOut(1500);
    }
    });

    メニューボタンとメニューをひとつのボックスに入れて、そのボックスごとアニメーションさせる方法もとってみたのですが、そうするとこのボックスを最上部レイヤーにもってきたとき、下に重なっているクリックボタンなどがメニューボタンの幅分クリックできなくなってしまいましたので、上記のような形に落ち着きました。

    もし見ていただいていたようでしたら、お手間をおかけして申し訳ありませんでした。
    ありがとうございました。

コメントを残す

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