2018/1/20 訂正箇所があったので修正しました。
いろんなライブラリ試してきたけど、、結局これが一番簡単で使いやすい。
でも、「こうだったらいいのになぁ・・・」とかがないわけではない。
私が使いやすいようにカスタマイズしたもののメモです。
簡単に多階層レスポンシブメニューを実装できるjQuery「meanmenu.js」
もくじ
meanmenu万能!
設置方法は前の記事で紹介しています。
今回はカスタマイズについてがメインの記事になります。
まず私が動きとしてカスタマイズしたかったことは以下。
- ヘッダーを固定したときにメニューがスマホ画面の縦より長い場合、スクロールできないからできるようにしたい。
- 逆にスマホ画面縦より短い場合はメニュー外にオーバーレイマスクを表示→タップでメニューを閉じたい。
- メニューを開いてるときは背景をスクロールできないようにしたい。
- ハンバーガーボタンをカスタマイズしてアニメーションさせたい。
デモを用意してみました。
普段meanmenuを使用する際には、
PC用にはcssのみで下層も含め表示させ、スマホ用にmeanmenuを使っています。
幅を狭めてみてスマホ用の表示を確認してみてください。
meanmenuカスタマイズデモ
基本html
デモのヘッダー全体含めたHTMLのコードです。
メニュー部分のみの場合は、nav部分をどうぞ。
オーバーレイマスクを追加するために、navのulが終わった直後に
<div class="mask"></div>
を追加しているので忘れずにね。
<header id="header">
<div class="container">
<div id="h_top">
<div class="h_logo"><a href="https://webmoyou.com"><img src="img/logo.png" alt="うぇぶもよう"></a></div>
<div class="h_nav">
<nav id="gNav">
<ul class="nav">
<li>
<a href="">MENU<i class="fa fa-angle-down"></i></a>
<ul class="sub-menu">
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
</ul>
</li>
<li>
<a href="">MENU<i class="fa fa-angle-down"></i></a>
<ul class="sub-menu">
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
<li><a href="">submenu</a></li>
</ul>
</li>
<li><a href="">MENU</a></li>
<li><a href="">MENU</a></li>
<li><a href="">MENU</a></li>
</ul>
<div class="mask"></div>
</nav>
</div>
</div>
</div>
</header>
カスタマイズした箇所
head内に記述します。
ハンバーガーメニューをクリックしたときに.fixedというclassを付与。そして.maskを表示。
また、.maskをクリックでもメニューを閉じれるように。
特になにも指定しないとbody直下にmeanmenuが表示されるのですが、リンク付きのロゴを配置する場合
上にmeanmenuが重なってしまうためmeanmenuの表示位置を指定しています。
ロゴはz-indexでmeanmenuの上に重なるように指定。
<script type="text/javascript">
$(function($){
//メニューの表示状態保管用
var state = false;
//.bodyのスクロール位置
var scrollpos = 0;
//meanmenuの状態による表示制御
function mm_control() {
if($('.mean-nav .nav').is(':visible')) {
//表示中
if(state == false) {
scrollpos = $(window).scrollTop();
$('body').addClass('fixed').css({'top': -scrollpos});
$('.mean-container').addClass('open');
$('.mean-nav .mask').show();
state = true;
}
} else {
//非表示中
if(state == true) {
$('body').removeClass('fixed').css({'top': 0});
window.scrollTo( 0 , scrollpos );
$('.mean-container').removeClass('open');
$('.mean-nav .mask').hide();
state = false;
}
}
}
$('#gNav').meanmenu({
meanMenuContainer: "#header .h_nav", // メニューを表示させる位置
meanScreenWidth: "768"
});
$(document)
.on('opend.meanmenu closed.meanmenu', function() {
mm_control();
})
.on('touchend click', '.mean-bar .mask', function(e) {
$('.mean-bar .meanmenu-reveal').trigger('click');
return false;
});
//ウィンドウサイズ変更によるメニュー非表示時の制御
$(window).on('resize', function() {
mm_control();
});
});
</script>
cssでオーバーレイマスクを追加する!
上記で.maskというクラスがあったら、メニューボタンタップ(もしくはクリック)で表示、
そしてマスクもしくはメニューボタン(クローズボタン)クリックで非表示という命令をしています。
なので今度はcssでオーバーレイマスクの見た目を調整します。
@media only screen and ( max-width : 768px ) {
#header .mask {
background: rgba(22,34,42,.4);
top: 60px;
left: 0;
z-index: 1;
position: absolute;
width: 100%;
height: 100vh;
opacity: 1;
display: none;
}
}
背景固定する!
@media only screen and ( max-width : 768px ) {
.fixed {
position: fixed;
width: 100%;
height: 100%;
z-index: 1;
}
}
ハンバーガーボタンをアニメーションさせる
アニメーションについては、こちらの記事を参考にさせていただきました。
さらに、ハンバーガーボタン部分のHTMLはmeanmenu.jsの中で指定しているため、修正しています。
ハンバーガーアニメーションを利用しない場合は、meanmenu.jsを変更する必要はありません。
参考に、記事の最後に今回カスタマイズしたHTMLデータをダウンロードできるようにしておきました。
これで追加部分は完了です。
meanmenu.css
参考までに私のカスタマイズしたmeanmenu.cssを載せておきます。
a.meanmenu-reveal{
display:none;
}
.mean-container .mean-bar{
width:100%;
position:fixed;
background:none;
min-height:60px;
z-index:999998;
top:0;
left:0;
}
.mean-container .mean-bar {
width: 100%;
position: fixed;
background: none;
min-height: 60px;
z-index: 98;
top: 0;
left: 0;
}
.meanmenu-reveal-btn {
position: absolute;
display: block;
z-index: 99999;
box-sizing: border-box;
width: 60px;
height: 60px;
right: 0;
top: 0;
}
.meanmenu-reveal {
width: 26px;
height: 20px;
margin: 13px 17px 27px 17px;
display: block !important;
position: relative;
}
.meanmenu-reveal:after {
content: "MENU";
position: absolute;
bottom: -20px;
color: #6bb5cb;
font-size: 10px;
width: 60px;
left: -17px;
text-align: center;
display: block;
font-family:serif;
}
.meanmenu-reveal.meanclose:after {
content: "CLOSE";
}
.meanmenu-reveal span {
display: inline-block;
transition: all .4s;
box-sizing: border-box;
position: absolute;
left: 0;
width: 100%;
height: 2px;
margin: 0 auto;
}
.meanmenu-reveal span:nth-of-type(1) {
top: 0;
background: #6bcbba;
}
.meanmenu-reveal span:nth-of-type(2) {
top: 8px;
background: #6bcacb;
}
.meanmenu-reveal span:nth-of-type(3) {
top: 16px;
background: #6bbacb;
}
.meanmenu-reveal span:nth-of-type(1) {
-webkit-animation: menu-ber01 .75s forwards;
animation: menu-ber01 .75s forwards;
}
.meanmenu-reveal span:nth-of-type(2) {
transition: all .25s .25s;
opacity: 1;
}
.meanmenu-reveal span:nth-of-type(3) {
-webkit-animation: menu-ber02 .75s forwards;
animation: menu-ber02 .75s forwards;
}
.meanclose span:nth-of-type(1) {
-webkit-animation: active-menu-ber01 .75s forwards;
animation: active-menu-ber01 .75s forwards;
top: -2px;
}
.meanclose span:nth-of-type(2) {
opacity: 0;
}
.meanclose span:nth-of-type(3) {
-webkit-animation: active-menu-ber03 .75s forwards;
animation: active-menu-ber03 .75s forwards;
}
@-webkit-keyframes menu-ber01 {
0% {
-webkit-transform: translateY(8px) rotate(45deg);
}
50% {
-webkit-transform: translateY(8px) rotate(0);
}
100% {
-webkit-transform: translateY(0) rotate(0);
}
}
@keyframes menu-ber01 {
0% {
transform: translateY(8px) rotate(45deg);
}
50% {
transform: translateY(8px) rotate(0);
}
100% {
transform: translateY(0) rotate(0);
}
}
@-webkit-keyframes menu-ber02 {
0% {
-webkit-transform: translateY(-8px) rotate(-45deg);
}
50% {
-webkit-transform: translateY(-8px) rotate(0);
}
100% {
-webkit-transform: translateY(0) rotate(0);
}
}
@keyframes menu-ber02 {
0% {
transform: translateY(-8px) rotate(-45deg);
}
50% {
transform: translateY(-8px) rotate(0);
}
100% {
transform: translateY(0) rotate(0);
}
}
@-webkit-keyframes active-menu-ber01 {
0% {
-webkit-transform: translateY(0) rotate(0);
}
50% {
-webkit-transform: translateY(10px) rotate(0);
}
100% {
-webkit-transform: translateY(10px) rotate(45deg);
}
}
@keyframes active-menu-ber01 {
0% {
transform: translateY(0) rotate(0);
}
50% {
transform: translateY(10px) rotate(0);
}
100% {
transform: translateY(10px) rotate(45deg);
}
}
@-webkit-keyframes active-menu-ber03 {
0% {
-webkit-transform: translateY(0) rotate(0);
}
50% {
-webkit-transform: translateY(-8px) rotate(0);
}
100% {
-webkit-transform: translateY(-8px) rotate(-45deg);
}
}
@keyframes active-menu-ber03 {
0% {
transform: translateY(0) rotate(0);
}
50% {
transform: translateY(-8px) rotate(0);
}
100% {
transform: translateY(-8px) rotate(-45deg);
}
}
.mean-container .mean-nav{
width:100%;
margin-top:60px;
max-height:100vh;
overflow-y:auto;
}
.mean-container .mean-nav ul{
padding: 0;
margin: 0;
width: 100%;
list-style-type: none;
overflow-y: scroll;
-webkit-overflow-scrolling:touch;
position: relative;
z-index: 99;
max-height: 100vh;
max-height: calc(100vh - 60px);
background: #eef7f9;
}
.mean-container .mean-nav ul ul{
padding-bottom:0;
margin-bottom:0;
}
.mean-container .mean-nav ul li{
position:relative;
width:100%;
box-sizing: border-box;
}
.mean-container .mean-nav ul li a,.mean-container .mean-nav ul li span.pre{
display:block;
width:100%;
padding:1em;
margin:0;
text-align:left;
text-decoration:none;
text-transform:uppercase;
color:#477684;
box-sizing: border-box;
}
.mean-container .mean-nav ul li li a{
width:100%;
padding:1em 10%;
text-shadow:none !important;
visibility:visible;
}
.mean-container .mean-nav ul li.mean-last a{
border-bottom:none;
margin-bottom:0;
}
.mean-container .mean-nav ul li li li a{
width:70%;
padding:1em 15%;
}
.mean-container .mean-nav ul li li li li a{
width:60%;
padding:1em 20%;
}
.mean-container .mean-nav ul li li li li li a{
width:50%;
padding:1em 25%;
}
.mean-container .mean-nav ul li a:hover{
background:#252525;
background:rgba(255,255,255,0.1);
}
.mean-container .mean-nav ul li a.mean-expand{
/*margin-top:1px;*/
width:60px;
text-align:center;
position:absolute;
right:0;
top:0;
z-index:2;
padding: 0.2em;
font-size: 24px;
color: #6bb5cb;
}
.mean-container .mean-nav ul li a.mean-expand:hover {
background:#a0c6d1;
color: #fff;
}
.mean-container .mean-push {
float:left;
width:100%;
padding:0;
margin:0;
clear:both;
}
.mean-nav .wrapper{
width:100%;
padding:0;
margin:0;
}
.mean-container .mean-bar, .mean-container .mean-bar *{
-webkit-box-sizing:content-box;
-moz-box-sizing:content-box;
box-sizing:content-box;
}
.mean-remove{
display:none !important;
}
PC・スマホ共通css
#header {
box-shadow: 0px 3px 15px rgba(0,0,0,0.2);
z-index: 99;
width: 100%;
position: fixed;
top: 0;
left: 0;
background: #fff;
}
#gNav a:hover {
color: #999;
}
nav li a {
font-size: 13px;
letter-spacing: 0.2em;
}
nav .sub-menu,.mean-container .mean-nav ul ul {
background: #fff;
background-image: linear-gradient(to top, #fff1eb 0%, #ace0f9 100%);
}
スマホ用ヘッダー部分css
@media only screen and ( max-width : 768px ) {
#header {
padding: 10px 0;
height: 60px;
}
.h_logo {
width: 200px;
position: absolute;
top: 18px;
left: 10px;
z-index: 100;
}
#gNav .nav {
overflow-y: auto;
height: 100vh;
}
.mean-nav .container {
padding: 0;
}
nav li .fa {
display: none;
}
}
PC用の多階層(今回は第一階層まで)css
こちらも参考までにデモのPC用多階層に指定したcssを載せておきます。
@media print, screen and ( min-width : 769px ) {
#header {
height: 80px;
}
.h_logo img {
width: 300px;
}
#h_top {
display: flex;
justify-content: space-between;
align-items: center;
}
#gNav ul {
position: relative;
display: flex;
}
#gNav li {
position: relative;
margin-right: 3em;
}
#gNav li:last-child {
margin-right: 0;
}
#gNav li i {
font-size: 16px;
margin-left: 5px;
}
#gNav li a {
position: relative;
display: block;
text-align: center;
line-height: 80px;
}
#gNav .sub-menu {
visibility: hidden;
opacity: 0;
z-index: 1;
display: block;
position: absolute;
top: 50px;
left: 50%;
margin-left: -100px;
width: 200px;
-webkit-transition: all .2s ease;
transition: all .2s ease;
}
#gNav .sub-menu a {
padding: 10px;
display: block;
border-bottom: none;
padding: 20px;
line-height: 1.2em;
}
#gNav .sub-menu a:hover:after {
content: none;
}
#gNav .sub-menu li {
display: block;
font-size: 16px;
padding: 0;
margin: 0;
}
#gNav .sub-menu li:last-child {
border-bottom: none;
}
#gNav ul > li:hover {
-webkit-transition: all .5s;
transition: all .5s;
}
#gNav ul > li:hover a,#gNav .current-menu-item a,#gNav .current-menu-parent a {
color: #bfd0ff;
}
#gNav li:hover ul.sub-menu {
top: 80px;
visibility: visible;
opacity: 1;
z-index: 9999;
}
#gNav li ul li:after {
content: none;
}
#gNav li:hover ul.sub-menu a {
color: #111;
}
#gNav .sub-menu li a:hover {
background: #fff;
}
#gNav .contact_btn a:hover {
color: #fff;
}
}
サンプルのダウンロード
サンプルをダウンロードできるようにしました。
是非ご活用ください。
サンプルをダウンロードしたい方はこちら(zipファイルダウンロード)
最後に
今回はmeanmenu.jsのカスタマイズのメモでした。
書き方はもしかするともっと良い方法があると思いますが
検索しても全然出てこなかったので、自分のやりたかったことができたので大満足です。
全体的に掲載していたものを修正いたしました!