以下の情報の方が新しいものになりますので、よろしかったらご覧ください。
「レスポンシブ Web デザイン/開閉式ナビゲーションメニュー」
基本的(単純)なレスポンシブメニュー(Menu 部分をクリックするとメニューが展開されて表示されるようなメニュー)の作成に関するメモ。
PC などでの表示(メニューは横並び)
ヘッダ部分の「960×240」は特に意味はなし。ダミー画像。
<img src="http://dummyimage.com/960x240/666/fff" alt=""> <!-- 上記のように記述すると表示できる(参考) -->
スマートフォンなどでの表示
Menu 部分をクリック(タッチ)すると展開される
head 要素内に Viewport の指定をする。
(関連ページ:Viewport と Media Queries に関するメモ)
<meta name="viewport" content="width=device-width">
body 要素内にメニューの記述をする。
<div id="navi" class="clearfix"> <ul class="clearfix"> <li><a class="disabled" href="#">Top</a></li> <li><a href="en/schedule/schedule.html">Schedule</a></li> <li><a href="en/profile/profile.html">Profile</a></li> <li><a href="en/discography/discography.html">Discography</a></li> <li><a href="en/video/video.html">Video</a></li> <li><a href="en/contact/contact1.php">Contact</a></li> <li><a href="indexjp.html">Japanese</a></li> </ul> <a href="#" id="pull">Menu</a> </div><!-- end of #navi -->
メニュー項目の他に「id=”pull”」のリンクを追加している。これはスモールデバイス(スマートフォン等)での表示の際に「Menu」や「Close」と表示されるメニューの開閉用のリンク。
メディアクエリーはスマートフォンなどの小さなスクリーン用から記述。
メディアクエリーを使った部分では、メディアクエリーを指定していないデフォルトのスタイルシートとの差分を記述する。
以下は共通する部分とスモールデバイス(480px 未満の幅)用の記述。
#navi { margin-bottom : 1.5em; background-color: #000; border-top: 1px solid #827D7D; width: 100%; /* 幅を100%に */ z-index: 100; /* 必要に応じて */ margin-top: 0; } #navi ul { overflow : hidden; /* 必要に応じて */ margin: 0; padding: 0; } #navi ul li { width : 100%; /* 幅を100%に */ border-bottom: 1px solid #666; } #navi ul li a { display : block; text-align: center; color : #FFF; padding : 0.8em 0; } #navi ul li a:hover { color:#8FEDF1; background-color : #333; } #navi ul { display: none; /* スモールデバイスでは非表示に */ height: auto; } #navi a#pull { display: block; /* #pull のみ表示 */ background-color: #000; width: 100%; position: relative; text-align: center; font-size: 1.3em; color: #FFF; text-decoration: none; } #navi a:hover#pull { color: #99DDF5; } /* :after 擬似要素で #pull に背景画像を指定 */ #navi a#pull:after { content:""; background: url(../images/navi-icon.png) no-repeat; width: 30px; height: 30px; display: inline-block; position: relative; left: 35%; top: 5px; } /* :after 擬似要素でホバー時の背景画像を指定 */ /* スマートフォンなどでは「ホバー」はないので不要かも */ #navi a:hover#pull:after { content:""; background: url(../images/navi-icon-hover.png) no-repeat; width: 30px; height: 30px; display: inline-block; position: relative; left: 35%; top: 5px; } /*clearfix*/ .clearfix:after { content: ""; display: block; clear: both; } .clearfix { zoom: 1; }
「:before, :after 擬似要素」を使用する際、content プロパティは必要条件で、記述が無いと動作しないので、空の content プロパティを指定。
480px~767px
li 要素の横幅は「小数点以下のピクセルの計算」も参照
また、スクロールした際にメニューをjQuery などを使って position:fixed で固定する場合は高さを指定する必要がある。(関連ページ:position: fixed を使ってメニューを固定する際の注意点)
@media screen and (min-width : 480px){ #navi{ /* 必要に応じて高さを指定 */ } #navi a#pull { display: none; /* #pullリンクを非表示に */ } #navi ul { display: block; /* メニューを表示 */ } #navi ul li { width : 14.129464%; /* 幅を%で指定(項目数、マージン等を考慮) */ float : left; /* 水平方向に並べて表示 */ } #navi ul li a { padding : 0.9em 0; } }
768px~959px
@media screen and (min-width : 768px){ #navi ul li a { padding : 0.7em 0; } }
960px 以上
@media screen and (min-width : 960px) { #navi { width: 960px; /* メニュー(ナビ)の幅を固定 */ } #navi ul li a { padding : 0.6em 0; } }
「Menu」という表示(#pull)をクリックした際の動作を記述。
jQuery(function($){ var pull = $('#pull'); var menu = $('#navi ul'); var menuOpen = false; $(pull).on('click', function(e) { e.preventDefault(); if(menuOpen){ menu.slideUp(); menuOpen = false; pull.text('Menu'); }else{ menu.slideDown(); menuOpen = true; pull.text('Close'); } }); $(window).resize(function(){ var w = $(window).width(); if(w > 320 && menu.is(':hidden')) { menu.removeAttr('style'); } }); });
#pull の文字の表示を変更(Menu → Close)しない場合は、「slideToggle()」を使って簡単にできる。
jQuery(function($){ var pull = $('#pull'); var menu = $('#navi ul'); $(pull).on('click', function(e) { e.preventDefault(); menu.slideToggle(); }); $(window).resize(function(){ var w = $(window).width(); // :hidden の代わりに css('display') で判定 if(w > 320 && menu.css('display') == 'none') { menu.removeAttr('style'); } }); });
:after 擬似要素で #pull に背景画像を指定する代わりに、アイコンフォントを使う場合の例。
この例では背景画像の代わりに、「Font Awesome」の「fa-bars」を使用。
HTML(変更箇所のみ)
<a href="#" id="pull">Menu <i class="fa fa-bars"></i></a>
アイコンフォントの i 要素を float で右寄せして位置やサイズを調整。
CSS(変更箇所のみ)
a#pull i { float: right; line-height: 40px; padding-right: 20px; font-size: 150%; } /* 以下は不要なので削除 */ /* a#pull:after { content:""; background: url(../images/navi-icon-hover.png) no-repeat; width: 30px; height: 30px; display: inline-block; position: relative; left: 35%; top: 5px; } a:hover#pull:after { content:""; background: url(../images/navi-icon-hover.png) no-repeat; width: 30px; height: 30px; display: inline-block; position: relative; left: 35%; top: 5px; } */
jQuery では text() の代わりに html() を使用。
jQuery
jQuery(function($){ var pull = $('#pull'); var menu = $('#navi ul'); var menuOpen = false; $(pull).on('click', function(e) { e.preventDefault(); if(menuOpen){ menu.slideUp(); menuOpen = false; //以下が変更箇所 pull.html('Menu <i class="fa fa-bars"></i>'); }else{ menu.slideDown(); menuOpen = true; //以下が変更箇所 pull.html('Close <i class="fa fa-bars"></i>'); } }); $(window).resize(function(){ var w = $(window).width(); if(w > 320 && menu.is(':hidden')) { menu.removeAttr('style'); } }); });
スマートフォンなどでの表示
前述の例の「#pull」に該当する部分(メニュー開閉ボタン)が、以下の例では「#navControl」になっていて、「Menu」という文字は表示せず、アイコンのみ(画像を用意)。
<div id="navControl"> <a href="#" class="close">Navigation</a> </div> <div id="navi" class="clearfix"> <ul id="globalNav" class="clearfix"> <li><a href="index.html">HOME</a></li> <li><a href="news.html">NEWS</a></li> <li><a href="garelly.html">GARELLY</a></li> <li><a href="access.html">ACCESS</a></li> <li><a href="contact.html">CONTACT</a></li> </ul> </div><!-- end of #navi -->
メニュー開閉ボタンは、画像で表示するためテキストが表示されないようにする。
またJavaScript でナビゲーションを非表示にするので、480px 以上では「ul#globalNav」に「display: block !important」で CSS の指定を優先させている。(前述の例では、 $(window).resize() を使って対処)
#navControl a { /* メニュー開閉ボタンのスタイル */ display: block; overflow: hidden; width: 44px; height: 44px; /* 画像の位置指定は使用する画像により異なる */ background: #000 url(img/icon.png) no-repeat 0 0; text-indent: 100%; white-space: nowrap; } ul#globalNav { margin: 0; padding: 0; list-style-type: none; } ul#globalNav li a { display: block; padding: 10px; background: #333; color: #fff; text-decoration: none; } ul#globalNav li a:hover{ background-color: #003159; } /* 480px 以上 */ @media only screen and (min-width: 480px) { #navControl { display: none; /* メニュー開閉ボタンは非表示に */ } ul#globalNav { display: block !important; /* メニュー(ナビゲーション)は必ず表示 */ } ul#globalNav li { float: left; /* 横並びに */ width: 18.6324%; /* 幅の指定 */ margin-right: 1.7094%; /* 右マージンの指定 */ text-align: center; } ul#globalNav li:last-child { margin-right: 0; /* 最後の要素は右マージン無し */ } }
このサンプルの場合、以下のように想定。
メニュー開閉ボタン(#navControl a)のクラス属性が「close」の場合(初期値)は、メニューを非表示にする。CSS で非表示にしてしまうと JavaScript がオフの場合メニューが表示されなくなるため JavaScript で非表示にする。
メニュー開閉ボタンをクリックした時、クラス属性が「close」の場合、メニューをスライドダウンして表示し、クラス属性を一度削除後、「active」に変更。
メニュー開閉ボタンのクラス属性が「close」の以外の場合、メニューをスライドアップして非表示(display:none)にし、クラス属性を「close」に変更。
但し、480px 以上の場合は CSS に「display: block !important」で指定してあるので表示される。
$(function () { if($('#navControl a').attr('class') == 'close'){ $('#globalNav').css('display', 'none'); } $('#navControl a').click(function() { if($(this).attr('class') == 'close'){ $('#globalNav').slideDown(); $(this).removeClass(); $(this).addClass('active'); }else{ $('#globalNav').slideUp(); $(this).removeClass(); $(this).addClass('close'); } }); });
メニュー開閉ボタン(#navControl a)のクラス属性「active」を使用して、表示を変更したりしなければ、「slideToggle()」と「toggleClass()」を使って以下のようにも記述可能。
$(function () { if($('#navControl a').attr('class') == 'close'){ $('#globalNav').css('display', 'none'); } $('#navControl a').click(function() { $('#globalNav').slideToggle(); $(this).toggleClass('close'); }); });
HTML から前述のメニューの開閉ボタンを構成する要素を削除して、jQuery で追加する。
<div id="navi" class="clearfix"> <ul id="globalNav" class="clearfix"> <li><a href="index.html">HOME</a></li> <li><a href="news.html">NEWS</a></li> <li><a href="garelly.html">GARELLY</a></li> <li><a href="access.html">ACCESS</a></li> <li><a href="contact.html">CONTACT</a></li> </ul> </div><!-- end of #navi -->
prepend() を使用してメニューの開閉ボタンを構成する要素を追加するだけ。(後は同じ。 CSS も同じ)
$(function () { $('#navi').prepend('<div id="navControl"><a href="#" class="close">Navigation</a></div>'); if($('#navControl a').attr('class') == 'close'){ $('#globalNav').css('display', 'none'); } $('#navControl a').click(function() { if($(this).attr('class') == 'close'){ $('#globalNav').slideDown(); $(this).removeClass(); $(this).addClass('active'); }else{ $('#globalNav').slideUp(); $(this).removeClass(); $(this).addClass('close'); } }); });
ブラウザによって小数点以下のピクセルを持った場合の計算の仕方が異なる。
このため、場合によってはメニューの項目が全体に収まりきらず、落ちてしまうことがある。
IE7 以下でも対応させる場合には、メニューの項目の幅の合計が 100% にするのではなく、少し余裕を持たせると良い。
IE7 は小数点以下のピクセルを計算する際に、0.5px 以上は切り上げするので 0.5px より小さい幅となるように「0.5px ÷ 親要素の幅 X 100%」を width の値から引くようにする。親要素の幅は最小のときの幅を使う。
この例の場合、7項目あるので単純に7で割ると「14.285714%」
上記の算出方法を適用すると
14.285714 – (0.5 ÷ 320 X 100) = 14.129464%
また、逆にピクセルが足りない場合も発生するので、親要素の ul 要素などに背景色を設定しておくとよい。