こんにちは、daimaです。
本日は私も業務でよく使っている
おしゃれでコンパクトな
ハンバーガーメニューのサンプルコードを
コピペしてすぐに使える形でご紹介したいと思います。
最終更新2021/01/30 :
・ナビ部分の開閉の仕組みを調整(画像など張り付けた時にずれて移動してしまっていたのを修正)
・ナビの中身のheightがナビのheightを超えた場合にスクロールが効くように修正
- レスポンシブ対応のハンバーガーメニューをコピペで簡単に設置したい
- ハンバーガーボタンはスクロールしてもずっとついてきて欲しい
- ナビが開いているときにナビ以外の部分をクリックしたらナビを閉じてほしい
- ナビが出現するときは画面端からスムーズに出現してほしい
- 細かいデザインや動きは自分で調整したい
- 最新の主要ブラウザ(Chrome、EDGE(IE)、Firefox、safari)に対応していてほしい
このような要件を満たす
ハンバーガーメニューをお探しの方は
ぜひ今回のコードを試してみてください。
デモとソースコード
<div class="el_humburger"><!--ハンバーガーボタン--> <div class="el_humburger_wrapper"> <span class="el_humburger_bar top"></span> <span class="el_humburger_bar middle"></span> <span class="el_humburger_bar bottom"></span> </div> </div> <header class="navi"><!--ナビゲーション--> <div class="navi_inner"> <div class="navi_item"><a href="">ABOUT</a></div> <div class="navi_item"><a href="">WORKS</a></div> <div class="navi_item"><a href="">GALLERY</a></div> <div class="navi_item"><a href="">FLOW</a></div> <div class="navi_item"><a href="">FAQ</a></div> <div class="navi_item"><a href="">CONTACT</a></div> <div class="navi_item"><a href="">TEST1</a></div> </div> </header> <div class="mainView"> <!--ページコンテンツ--> </div> <!--CDNでjQuery読み込む--> <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
body{ margin: 0; } a{ color: #040404; text-decoration: none; } .mainView{ width: 100vw; height: 100vh; background-color: #ccc; } /*ハンバーガーボタン*/ .el_humburger { position: fixed; top: 45px; right: 60px; width: 46px; height: 25px; padding-top: 1px; -webkit-box-sizing: border-box; box-sizing: border-box; padding-top: 0px; z-index: 20; cursor: pointer; pointer-events: auto; color: #000; text-align: center;} @media screen and (max-width: 840px) { .el_humburger { display: block; right: 0; top: 0; padding-top: 20px; width: 70px; height: 70px;} #factory .el_humburger { display: none; } } .el_humburger_wrapper { margin-bottom: 5px; width: 42px; display: inline-block; } @media screen and (max-width: 840px) { .el_humburger_wrapper { margin-bottom: 5px; width: 30px; } } .el_humburger_text { font-size: 12px; letter-spacing: 0.1em; font-family: "游ゴシック Medium", YuGothic, "Yu Gothic", "ヒラギノ角ゴ Pro", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, sans-serif; } .js_humburgerOpen .el_humburger_text.el_humburger_text__menu { display: none; } .el_humburger_text.el_humburger_text__close { display: none; } .js_humburgerOpen .el_humburger_text.el_humburger_text__close { display: block; } @media screen and (max-width: 840px) { .el_humburger_text { font-size: 10px; padding-top: 2px; } } @media screen and (max-width: 840px) { .el_humburger_text svg path { -webkit-transition: all 200ms cubic-bezier(0.16, 0.52, 0.25, 1); -o-transition: all 200ms cubic-bezier(0.16, 0.52, 0.25, 1); transition: all 200ms cubic-bezier(0.16, 0.52, 0.25, 1); fill: #000; } } @media screen and (max-width: 840px) { .js_humburgerOpen .el_humburger_text svg path { fill: #000; } } .el_humburger span.el_humburger_bar { display: block; width: 100%; margin: 0 auto 9px; height: 1px; background: #000; -webkit-transition: all .2s ease-in-out; -o-transition: all .2s ease-in-out; transition: all .2s ease-in-out; } .el_humburger span.el_humburger_bar:last-child { margin-bottom: 0; } .js_humburgerOpen .el_humburger span.el_humburger_bar { background: #000; } @media screen and (max-width: 840px) { .el_humburger span.el_humburger_bar { left: 0; top: 0; background: #000; } } .js_humburgerOpen .el_humburger span.el_humburger_bar.top { -webkit-transform: translateY(9px) rotate(-45deg); -ms-transform: translateY(9px) rotate(-45deg); transform: translateY(9px) rotate(-45deg); } .js_humburgerOpen .el_humburger span.el_humburger_bar.middle { opacity: 0; } .js_humburgerOpen .el_humburger span.el_humburger_bar.bottom { -webkit-transform: translateY(-11px) rotate(45deg); -ms-transform: translateY(-11px) rotate(45deg); transform: translateY(-11px) rotate(45deg); } .el_humburgerButton.el_humburgerButton__close { top: 2%; right: 2%; } .el_humburgerButton__close span.el_humburger_bar { display: block; width: 35px; margin: 0 auto; height: 4px; background: #000; } .el_humburgerButton__close span.el_humburger_bar.top { -webkit-transform: translateY(5px) rotate(-45deg); -ms-transform: translateY(5px) rotate(-45deg); transform: translateY(5px) rotate(-45deg); } .el_humburgerButton__close span.el_humburger_bar.bottom { -webkit-transform: translateY(-6px) rotate(45deg); -ms-transform: translateY(-6px) rotate(45deg); transform: translateY(-6px) rotate(45deg); } .navi { position: fixed; right: 0; height: 100%; background-color: rgba(255, 255, 255, 0.9); width: 450px; z-index: 3; padding-top: 100px; -webkit-box-sizing: border-box; box-sizing: border-box; -webkit-transition: all 600ms ease-out; -o-transition: all 600ms ease-out; transition: all 600ms ease-out; transform:translateZ(0) translateX(100%); overflow: auto; } .js_humburgerOpen .navi { right: auto; transform:translateZ(0) translateX(0); } @media screen and (max-width: 840px) { .navi { padding: 100px 5% 0; } .js_humburgerOpen .navi { width: 100%;} } .navi_item { margin-bottom: 28px; font-size: 20px; font-family: "Marcellus", serif !important; white-space: nowrap; margin-left: 90px; } .navi_item.op_innerLink { cursor: pointer; } @media screen and (max-width: 840px) { .navi_item { margin-left: 0; font-size: 18px; } }
//変数定義 var navigationOpenFlag = false; var navButtonFlag = true; var focusFlag = false; //ハンバーガーメニュー $(function(){ $(document).on('click','.el_humburger',function(){ if(navButtonFlag){ spNavInOut.switch(); //一時的にボタンを押せなくする setTimeout(function(){ navButtonFlag = true; },200); navButtonFlag = false; } }); $(document).on('click touchend', function(event) { if (!$(event.target).closest('.navi,.el_humburger').length && $('body').hasClass('js_humburgerOpen') && focusFlag) { focusFlag = false; //scrollBlocker(false); spNavInOut.switch(); } }); }); //ナビ開く処理 function spNavIn(){ $('body').removeClass('js_humburgerClose'); $('body').addClass('js_humburgerOpen'); setTimeout(function(){ focusFlag = true; },200); setTimeout(function(){ navigationOpenFlag = true; },200); } //ナビ閉じる処理 function spNavOut(){ $('body').removeClass('js_humburgerOpen'); $('body').addClass('js_humburgerClose'); setTimeout(function(){ $(".uq_spNavi").removeClass("js_appear"); focusFlag = false; },200); navigationOpenFlag = false; } //ナビ開閉コントロール var spNavInOut = { switch:function(){ if($('body.spNavFreez').length){ return false; } if($('body').hasClass('js_humburgerOpen')){ spNavOut(); } else { spNavIn(); } } };
多階層(子ページ有り)のバージョン
今回のハンバーガーメニューと同じデザインで
子ページへのリンクを追加したバージョンのコードを
以下の記事内で紹介しています。
子ページへのリンクを開閉式で表示できるハンバーガーメニューのサンプル | Webコーダーdaimaの備忘録
多階層のナビゲーションが必要な方は
こちらを参考にしてください。
おわりに
今回のハンバーガーメニューは
非常にシンプルな造りなので
比較的改変もしやすいかと思います。
もし他にもこんな機能があればよいのに
というご要望があればコメント欄にご意見をお寄せください。
それでは。
コメント
初めまして。質問させていただきます。
現在、ボタン「×」以外のところをクリックしてもナビを閉じることができます。
これを、ボタン「×」をクリックした時にだけナビを閉じるようにするにはどうすればよいでしょうか?
初歩的な質問で大変恐縮ですが、ご教授いただけないでしょうか?よろしくお願いします。
yakisobaforeverさんコメントありがとうございます。
ボタン以外の場所をクリックした際にメニューが閉じないようにしたい場合は
javascriptコードの19~25行目を以下の様にコメントアウトしてみてください。
————————————
//ハンバーガーメニュー
$(function(){
$(document).on('click','.el_humburger',function(){
if(navButtonFlag){
spNavInOut.switch();
//一時的にボタンを押せなくする
setTimeout(function(){
navButtonFlag = true;
},200);
navButtonFlag = false;
}
});
/*$(document).on('click touchend', function(event) {
if (!$(event.target).closest('.bl_header,.el_humburger').length && $('body').hasClass('js_humburgerOpen') && focusFlag) {
focusFlag = false;
//scrollBlocker(false);
spNavInOut.switch();
}
});*/
});
————————————
コードの公開ありがとうございます。
ハンバーガーメニューを押した後、横から出てくる範囲にheaderに付与したbackground-imageが反映されてしまうのですが、どのようにしたら解除されますでしょうか?
ご回答のほどよろしくお願いします。
ayakaさん お返事遅くなりすみません。
こちら、掲載コードのheaderタグを別のタグ(divなど)に置き換えて頂ければ大丈夫かと思います。
こんにちは、はまちゃんです。
ハンバーガーメニューのサンプルを色々探してやっと理想のコードにたどり着きました。
一点だけうまくいかない点があり、質問させてください。
メニューが多階層の場合、どのようにしたら対応出来ますでしょうか。
ご教授のほど、よろしくお願いいたします。
はまちゃんさん、ご訪問ありがとうございます。
当サイトのコードがご期待に沿えたようで私も嬉しく思います。
https://spreadsheep.net/page-848/
こちらはコメント頂いたページのハンバーガーメニューに
開閉式の子ページ一覧表示機能を追加した別バージョンのデモページです。
(各メニュー右の+ボタンクリックで子ページ一覧を開閉可)
このような仕様ではいかがでしょうか?
明けましておめでとうございます。
こんなに早く対応頂きありがとうございました。
素晴らしいの一言です。
心から感謝いたします。m(_ _)m
明けましておめでとうございます。
ご希望に沿えたようでなによりです。
https://spreadsheep.net/post-860/
今回作成したコードの内容をまとめた記事を投稿しましたので
よろしければ参考にしてみてください。それでは。
いつもこちらのコードを活用させていただいております!
1点お訊きしたいのですが、メニューに画像を入れて右寄せしようと試みています。
その場合、メニューを閉じる際に画像がおかしな挙動をします。(具体的にはメニューが閉じきる直前まで画像が残留する。)
こちらの問題の解消方法を教えていただけませんでしょうか?
ぴさん コメントありがとうございます。
当サイトのコードを活用して頂いているという事で嬉しく思います。
画像を追加した際に挙動がおかしくなるとのことですが、
検証のため実際のコードか実装されたページのURLなど共有して頂くことは可能でしょうか?
ほぼ全て引用させていただいた即興のものになりますが、メニューの1番上に画像を追加しています。
左端まで押し出されるのではなく、閉じた瞬間からメニューの動きに合わせて見えなくなっていってほしいです。
拙い説明で申し訳ございません。
上手くURLが貼れておりませんでした。
こちらよりご確認のほどお願いいたします。
https://liveweave.com/Ibz6T2#&togetherjs=CVQCm82J2V
ぴ さん コードの共有ありがとうございます。
https://spreadsheep.net/humburger-menu-for-pi/
こちらに修正を施したコードを掲載しました。
このような形でいかがでしょうか?(コードは全てソースから確認可能です)
確認いたしましたが、想定していた動作そのものでした!
本当にありがとうございます!
非常に分かりやすい記事でありがたいです。
jqueryではなく、javascriptでのコードを教えていただけないでしょうか。
お返事遅くなりすみません。
こちら、現在はjQueryを利用した実装のみの提供となっております。
ご期待に沿えず申し訳ないのですが、よろしくお願いします。
こんばんは。先月利用伺いをメールさせて頂きました。その節は有難うございます。
まだ自身でしか使っておりませんが、とてもスタイリッシュなハンバーガー&ドロワーメニューでとても気に入っております。
折角メニューを隠しているのに邪道な表示形態だとは思うのですが…
PCの大きな画面の時にハンバーガーボタンが遠くなってしまうので、一定サイズ以上の場合のみドロワー部を開いて表示させたいと思い、下記のようなscriptを作りました。
当方JS等に明るくない故、構文が正しいかどうか分かりません。
一応動くのですが、何か問題点が有ればお教え頂けると有難いです。
$(window).on(‘load resize’, function() {
var winW = $(window).width();
var devW = 1720;
if (winW <= devW) {
$("body").addClass("js_humburgerClose");
} else {
$("body").addClass("js_humburgerOpen");
}
});
akiさん お久しぶりです。
ご質問のコードを拝見しました。
私から見て、構文に特に大きな問題はない様に見受けられます。
その上で一点だけ気になったのは
ウィンドウ幅取得に利用されている$(window).width();です。
こちらの関数は正確には
「ウィンドウ幅からスクロールバーの幅を除いた幅」を取得する関数であり、
ブラウザによって取得される数値に僅かな誤差が出てしまう場合があります。
ですのでこちらはブラウザ間の誤差なくウィンドウ幅を取得できる
window.innerWidthにしておくとより良いかと思います。
お返事頂き有難うございます。
コメントした後、スクロールバー分としてサイズを20px増やし var devW=1740; として使っています。
当方jQuery v3.5.1 なので、jQuery(window).outerWidth() の利用を考えているのですが、どう思われますか?
出来ればJSでは無くjQueryを使いたいのです。ご意見を頂ければ幸いです。
akiさん お返事ありがとうございます。
jQueryのouterWidthメソッドですね。
自分の場合ウィンドウ幅の取得には大体innerWidthを使っていて、
不勉強ながら今まで殆ど利用したことがありませんでした。
勉強がてらChrome、Firefox、EDGEなどのブラウザで挙動を確かめてみましたが
確認した限りではinnerWidthと同じ値(=スクロールバーを除くブラウザの表示領域)を
安定して返していており、問題はなさそうでした。
その上で私なら同じケースであれば
やはりinnerWidthを使うかと思うのですが、
その理由も併せて提示しておきます。
①これまでの経験上、stack overflowなどでウィンドウ幅を取得する方法として
ネイティブjsのclientWidthやinnerWidthの使用を推奨している解答をより多く目にしてきたこと。(jQueryを使用している場合でも)
例 : https://stackoverflow.com/questions/8794338/get-the-height-and-width-of-the-browser-viewport-without-scrollbars-using-jquery
②https://api.jquery.com/outerWidth/
jQueryの公式リファレンスのouterWidthの説明ページに
「This method is not applicable to window and document objects(このメソッドはwindow及びdocumentオブジェクトに対しては利用できません)」
といった記載があること。(その割にちゃんと数値を取得してくるのが謎ですが)
③jQueryはjavascirptの集合体であり、jQueryで出来ることは全て生のjavascriptでも再現可能。
その上でjQueryに依存しない方法に普段から慣れておくことで、jQueryが使えない環境でも応用が利くようにするため。
以上が現在の私の見解です。長文になってしまい済みません。
色々と書きましたが、私の知識も全く完全ではないですので
最終的にはakiさんご自身で情報を集めてみて、
総合的に判断して決定されるのが良いかと思います。
お返事頂き有難うございます。
ネイティブJSへの書き換えが難しいので(というかよく分からないので)敬遠してきたのですが、もっと勉強しようと思います。
大変為になるご意見、有難うございました。
こんにちは。何度も失礼致します。結局下記のような形に致しました。
$(window).on(‘load’, function() {
var winW = window.innerWidth;
var devW = 1740;
if (winW <= devW) {
$('body').addClass('js_humburgerClose').removeClass('js_humburgerOpen');
} else {
$('body').addClass('js_humburgerOpen').removeClass('js_humburgerClose');
}
});
一応報告に参りましたのは、先のScriptで.on(‘load resize’, function() {
にしていた事により、iPhoneで最下・最上へスクロールしてドロワーメニューをスワイプすると、ドロワーメニューが引っ込んでしまう不具合を見付けたからです。(Androidは未検証です。)
考え得る理由としては「画面スクロールの最下・最上で下から出現するツールバーにより画面がリサイズされたと見なされて、ツールバーが下から出る度にドロワーメニューが引っ込んでしまったようです。
…こんな事が有ったよ、という報告だけさせて頂きます。m(__)m
.on(‘load’, function() { のクオートが間違えているようなので訂正です。度々スミマセン。
.on(‘load’, function() { です。
コメント欄へのJSの書き込みに問題が有るようなら削除して下さい。
akiさん ご丁寧に報告いただきありがとうございます。
お話の不具合について、こちらでも実機で確認することができました。
この点、デバイスに関わる問題で中々困ったところですが、
ひとつ思いつく対策としては、
例えば以下の記事で紹介しているメニューの様に
ナビが開いている場合にはそもそもウィンドウ側のスクロールを
無効にしてしまう事で問題の発生を防ぐことができるかもしれません。
https://spreadsheep.net/post-240/
古い記事という事もあり、今見るとコードに
いくつか改善の必要な点もありますがご参考までに。
こんばんは。お返事有難うございます。
お教え頂いたbody fixedも良いですね。これから色々勉強したいと思います。
この度は有難うございました。
いつも利用させて頂いております。
こちら1000px以上の画面の時に、ハンバーガーメニューをなくして
nav メニューを横に表示したいのですが、どう実装したらよいでしょうか。
el_humburgerをdisplay:noneにして、とかいろいろやっておりのですが、
なかなかうまくいきません。
よろしくお願いいたします。
shuttyさんコメントありがとうございます。
https://barber6.com/
https://mena.co.jp/
これらのサイトのナビなど、shuttyさんのしたい事に近いように思いますので
よろしければソースコード等見てみてご参考にしてみると解決のヒントになるかもしれません(違ってたらごめんなさい)
こんにちは。
こちらのコードを使用させていただきました。
ありがとうございます。
ページ内リンクにしているのですが、メニューリンクをクリックした後に、メニューが閉じません。
色々記述してみたのですが、わかりません。
何か方法はございますでしょうか。
何卒、よろしくお願いいたします。
kickさん コメントありがとうございます。
お返事遅くなりすみません。
ご相談の点について対応したサンプルを作ってみました。
https://spreadsheep.net/page-1087/
元記事からの変更点は
(内部リンク再現用のHTMLを除けば)scriptタグ内の「/*追加*/」というコメントアウトより下のjavascript記述のみですので、
もし既に元記事のハンバーガーメニューを導入済であれば、
その個所だけコピペで追加して頂ければサンプルと同じように動作するかと思います。
(コード確認用のショートカットキーはWindowsなら「Ctrl + U」、macなら「option + command + U」です。)
もし思っていたのと違っていたり上手く動かなかったりした場合はまた教えてください。
よろしくお願いします。
こんにちは。
素敵なコードありがとうございます。
現在、html css jqueryについて勉強中の身です。
勉強用のページで上記のコードを使わせていただき、色や細かなところはcssで変更させていただいております。
そこで、質問なのですが、右側からメニューが出てきたあとに、メニュー以外の箇所(画面で言えば左7割ほど)の箇所を少し暗くしたいのですが、そういったコードを教えていただけませんか?
また、レスポンシブの場合に、右からにゅっと出てくるのではなく、画面全体に浮き出てくるようなコードも出来れば教えていただけないでしょうか?
不躾な質問ですみません。
もしよければ、よろしくお願いします。
当サイトにご訪問いただきありがとうございます。
現在html css jqueryについて勉強されているということで、当サイトが少しでもお役に立てれば幸いです。
ご質問の、メニューを開いたときに背景を暗くする処理についてですが、
私であればページ内に背景用のタグを設置しておいて、
そのタグを、メニューを開いたときにbodyに付与される「js_humburgerOpen」クラスが親にある場合のみ表示させるといった形で対応するかと思います。
具体的には…
[html]
id="menu-background"のdivタグ(中身は空でOK。body直下に配置)
[css]
#menu-background{
display:none;
position:fixed;
top:0;
left:0;
bottom:0;
right:0;
background-color:rgba(0,0,0,0.2);
z-index:2;
}
body.js_humburgerOpen #menu-background{
display:block;
}
このようなコードをデモのコードに足せば、
ご要望の仕様が実現できるのではないかと思います。
よろしければ一度お試しください。
いつも参考にさせて頂いております。
こちらのコードを実装させていただいておりますが、スマホで表示する際、閉じ際で引っかかるような挙動が発生してしまいます。こちらをスムースに閉じるためにはどのコードをどのようにいじればよいのでしょうか?
ご確認いただけると幸甚です。
原博規さん 不具合のご報告ありがとうございます。
ご報告いただいた問題について、こちらも手持ちのipod touchで同様の現象の発生が確認ができました。
現状デモのみですが、一部CSSを調整し
手持ちの実機ではスクロール時のがたつきが無くなったことを確認しました。
https://spreadsheep.net/side-in-humburgermenu-demo/
お手数ですが上記デモで再度ご確認いただき、
そちらの環境でも問題解消されていれば本記事のコード内容に調整内容を反映させたいと思います。
よろしくお願いします。
ようやくたどり着いた感のある、素晴らしいdrawerメニューをありがとうございます。
使用にあたって、一点ご確認いただきたい点があります。
iPhoneでの確認ですが、縦使用のときのみドロワーが閉じるときにスムースに閉じません。
横使用にすると問題なしです。
https://spreadsheep.net/side-in-humburgermenu-demo/
での確認ですので、私の設定ミスではないと思います。
お時間のあるときに、ご確認ください。
pooさん 不具合のご報告ありがとうございます。
ご報告いただいた問題について、こちらも手持ちのipod touchで同様の現象の発生が確認ができました。
現状デモのみですが、一部CSSを調整し
手持ちの実機ではスクロール時のがたつきが無くなったことを確認しました。
https://spreadsheep.net/side-in-humburgermenu-demo/
お手数ですが上記デモで再度ご確認いただき、
そちらの環境でも問題解消されていれば本記事のコード内容に調整内容を反映させたいと思います。
よろしくお願いします。
こちらのコードをコピペで活用させて頂いております。
一点、挙動がおかしいのでご助力願います。
メニューを閉じる間際(メニュー文字の先頭あたり)でいったん止まってから閉じる動きをします。こちらをスムースに閉じるためにはどうしたらよいのでしょうか?
PC画面より検証でモバイル表示して確認する際にはそのような挙動はなく、モバイル端末で確認すると上記挙動が発生します。
非常に困っており、本サイトにたどり着きました。
ご確認をお願いできれば幸いです。
原さん 不具合のご報告ありがとうございます。
ご報告いただいた問題について、こちらも手持ちのipod touchで同様の現象の発生が確認ができました。
現状デモのみですが、一部CSSを調整し
手持ちの実機ではスクロール時のがたつきが無くなったことを確認しました。
https://spreadsheep.net/side-in-humburgermenu-demo/
お手数ですが上記デモで再度ご確認いただき、
そちらの環境でも問題解消されていれば本記事のコード内容に調整内容を反映させたいと思います。
よろしくお願いします。