レスポンシブWebデザインに対応したメニューの作り方【追記あり】
レスポンシブに対応した横メニューを作る機会があったので、せっかくですし作り方を紹介したいと思います。お役に立てばうれしいです。
元々のタイトルは「レスポンシブWebデザインに対応した横メニューの作り方」でしたが、よく考えるとスマホ対応になったら縦メニューになりますのでタイトルを変更しました。
できあがりはこちらのサンプルをご覧ください。
それでは作り方を解説していきます。
HTML
まずはHTMLです。
01 | <div id="menu-box"> |
02 | <div id="toggle"><a href="#">menu</a></div> |
03 | <ul id="menu" class=""> |
04 | <li><a href="#">html</a></li> |
05 | <li><a href="#">css</a></li> |
06 | <li><a href="#">javascript</a></li> |
07 | <li><a href="#">php</a></li> |
08 | <li><a href="#">CGI</a></li> |
09 | <li><a href="#">Python</a></li> |
10 | <li><a href="#">Ruby</a></li> |
11 | <li><a href="#">java</a></li> |
12 | </ul> |
13 | </div> |
id名「toggle」の部分は横幅が480px以下の場合に表示するボタンです。481px以上の場合表示させません。その他はごく普通の横メニューです。
CSS
続いてCSSです。まずは全体を載せます。
01 | #menu{ |
02 | width: 100%; |
03 | max-width: 960px; |
04 | margin: 0 auto; |
05 | padding: 0; |
06 | } |
07 | #menu li{ |
08 | display: block; |
09 | float: left; |
10 | width: 12.5%; |
11 | margin: 0; |
12 | padding: 0; } |
13 | #menu li a{ |
14 | display: block; |
15 | padding: 12px 0 10px; |
16 | background: #333; |
17 | color: #fff; |
18 | text-align: center; |
19 | text-decoration: none; |
20 | } |
21 | #menu li a:hover{ |
22 | background: #444; |
23 | } |
24 | #toggle{ |
25 | display: none; |
26 | } |
27 | @media only screen and (max-width: 768px) { |
28 | #menu li{ |
29 | width: 25%; |
30 | border-bottom: 1px solid #444; |
31 | } |
32 | } |
33 | @media only screen and (max-width: 480px) { |
34 | #menu{ |
35 | display: none; |
36 | } |
37 | #menu li{ |
38 | width: 100%; |
39 | } |
40 | #toggle{ |
41 | display: block; |
42 | position: relative; |
43 | width: 100%; |
44 | background: #222; |
45 | } |
46 | #toggle a{ |
47 | display: block; |
48 | position: relative; |
49 | padding: 12px 0 10px; |
50 | border-bottom: 1px solid #444; |
51 | color: #fff; |
52 | text-align: center; |
53 | text-decoration: none; |
54 | } |
55 | #toggle:before{ |
56 | display: block; |
57 | content: ""; |
58 | position: absolute; |
59 | top: 50%; |
60 | left: 10px; |
61 | width: 20px; |
62 | height: 20px; |
63 | margin-top: -10px; |
64 | background: #fff; |
65 | } |
66 | #toggle a:before, #toggle a:after{ |
67 | display: block; |
68 | content: ""; |
69 | position: absolute; |
70 | top: 50%; |
71 | left: 10px; |
72 | width: 20px; |
73 | height: 4px; |
74 | background: #222; |
75 | } |
76 | #toggle a:before{ |
77 | margin-top: -6px; |
78 | } |
79 | #toggle a:after{ |
80 | margin-top: 2px; |
81 | } |
82 | } |
では、部分ごとで解説していきます。
最初の状態
CSSはごく普通のメニューですので問題ないと思います。今回は横に8つ並ぶメニューですので、1つの横幅は12.5%にしています。
01 | #menu{ |
02 | width: 100%; |
03 | max-width: 960px; |
04 | margin: 0 auto; |
05 | padding: 0; |
06 | } |
07 | #menu li{ |
08 | display: block; |
09 | float: left; |
10 | width: 12.5%; |
11 | margin: 0; |
12 | padding: 0; } |
13 | #menu li a{ |
14 | display: block; |
15 | padding: 12px 0 10px; |
16 | background: #333; |
17 | color: #fff; |
18 | text-align: center; |
19 | text-decoration: none; |
20 | } |
21 | #menu li a:hover{ |
22 | background: #444; |
23 | } |
24 | #toggle{ |
25 | display: none; |
26 | } |
全体の横幅は100%ですが、1920pxなど大きなディスプレイで100%になると広すぎて逆に見にくいので、max-width: 960px;を指定しています。
最近はモバイルファーストで小さいディスプレイから設計する場合も多いようですが、IE8以下はメディアクエリに対応していないこともあり、今はまだPCから考える方がいいかと個人的には考えています。
もちろんIE8以下でもメディアクエリを有効にする方法はあります。下のコードを追加するだけです。
1 | <!--[if lt IE 9]> |
2 | <script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script> |
3 | <![endif]--> |
768px以下の場合
続いて、タブレットなどを想定した768px以下のディスプレイで見た場合のスタイルです。
1 | @media only screen and (max-width: 768px) { |
2 | #menu li{ |
3 | width: 25%; |
4 | border-bottom: 1px solid #444; |
5 | } |
6 | } |
メニューの幅を12.5%から25%へと倍にすることで、1列から2列になります。上下の区切りが分かるように下線を引いています。
横線を引いてもいいかもしれません。横線を引く場合は「box-sizing: border-box」を指定する必要があります。指定しないと3つで折り返してしまいます。
「box-sizing: border-box」については先日書いたこの記事をご参考に。
480px以下の場合
最後はスマホなど480px以下のディスプレイで見た場合のスタイルです。ここでガラッと変わります。初期状態ではメニューの内容は表示されず、「menu」と書かれたボタンのみ表示されています。その「menu」をクリックするとメニューの内容がスライドして現れます。
クリックしてメニューが現れる仕組みはjQueryで実装します。コードはCSSの後で紹介しています。
1 | @media only screen and (max-width: 480px) { |
2 | #menu{ |
3 | display: none; |
4 | } |
5 | #menu li{ |
6 | width: 100%; |
7 | } |
#menuの表示をいったん消して、メニュー1つの幅を100%にします。
01 | #toggle{ |
02 | display: block; |
03 | position: relative; |
04 | width: 100%; |
05 | background: #222; |
06 | } |
07 | #toggle a{ |
08 | display: block; |
09 | position: relative; |
10 | padding: 12px 0 10px; |
11 | border-bottom: 1px solid #444; |
12 | color: #fff; |
13 | text-align: center; |
14 | text-decoration: none; |
15 | } |
いったん消したメニューを開くためのボタンを作ります。最初に消していた#toggleをここで表示するようにします。後で指定する擬似要素の基準となるため、position: relativeを指定します。
最後に左のアイコンです。画像を使ってもいいですが、CSSで表現できるものはCSSでおこないたいです。
01 | #toggle:before{ |
02 | display: block; |
03 | content: ""; |
04 | position: absolute; |
05 | top: 50%; |
06 | left: 10px; |
07 | width: 20px; |
08 | height: 20px; |
09 | margin-top: -10px; |
10 | background: #fff; |
11 | } |
12 | #toggle a:before, #toggle a:after{ |
13 | display: block; |
14 | content: ""; |
15 | position: absolute; |
16 | top: 50%; |
17 | left: 10px; |
18 | width: 20px; |
19 | height: 4px; |
20 | background: #222; |
21 | } |
22 | #toggle a:before{ |
23 | margin-top: -6px; |
24 | } |
25 | #toggle a:after{ |
26 | margin-top: 2px; |
27 | } |
28 | } |
ちょっと分かりにくいかもしれませんのでボタンの構造を画像にしてみました。
白い正方形の上に黒い長方形を2つ乗せて3本線を表現しています。
この3つの要素はすべて擬似要素で作られています。この辺の使い方は慣れるまで難しいかもしれませんが、使い慣れるとCSSの幅がぐっと広がります。
では、縦の位置の調整について、ボタンの部分をもっと拡大して解説します。
top: 50%;を指定することで、擬似要素の上の位置が画像の点線部分になります。
白い正方形にあたる「#toggle:before」の場合は高さ20pxの半分にあたる10pxを「margin-top: -10px」で上げることで上下中央に表示されます。
続いて、白い正方形を区切る2つの黒い長方形について、「#toggle a:before」は真ん中の太い点線部分から6px上げて(上の点線)、「#toggle a:after」は点線部から2px下げて(下の点線)表示しています。
jQuery
#toggleを押してメニューを開く仕組みはjQueryで実装します。jQueryファイルは各自指定しておいてください。
コメント等で、スマホ対応の表示のときにメニューを開いて閉じてからウインドウサイズを大きくするとメニューが消えてしまうとのご指摘をいただきました。
実際使う場合ころころディスプレイサイズを変えることもないので対応しなかったのですが、iPhoneの縦から横にしたときなどはこの現象が起きてしまいますので対応しました。具体的には6行目以降が追加されています。
画面サイズが変わって480pxより広くなると「#menu」が表示され、480px以下の場合は表示されなくなります。
ご指摘いただいた皆様、ありがとうございました。
iosの場合、スクロールした際にresizeイベントが発生します。そのため、スクロールした際に開いたメニューが閉じてしまいます。
今回、下記の赤字の部分を削除することで対応しています。
今更で申し訳ございませんがよろしくお願いします。
if(win > p){
$("#menu").show();
} else {
$("#menu").hide();
}
ということで、以下のようになっています。
01 | $(function(){ |
02 | $("#toggle").click(function(){ |
03 | $("#menu").slideToggle(); |
04 | return false; |
05 | }); |
06 | $(window).resize(function(){ |
07 | var win = $(window).width(); |
08 | var p = 480; |
09 | if(win > p){ |
10 | $("#menu").show(); |
11 | } |
12 | }); |
13 | }); |
#toggleをクリックするたびに#menuがスライドして開閉します。jQueryを知らない方でもイメージできるようなシンプルなコードです。この辺がjQueryの親しみやすさかなと思ったりしています。
まとめ
ということで、レスポンシブにデザインする際に使えそうな横メニューの作り方を解説しました。
今回は8個のメニューということで、3パターンに変形するようにしました。これが7つになると2列にはしにくいので、今回のようにはいかないと思います。かといってあまり早い段階で縦1列にするとメニューの幅が広くなりすぎてスペースの無駄使いになります。
どのポイントでどのように変形させるかは、メニューの数によって様々だと思います。
また、メニューと直接関係ないかもしれませんが、3本線の作り方は役に立ちますので、ぜひ覚えていってください。
スマホサイズのときに一度メニューを開いて、閉じて、その後ウインドウサイズを広げると、ナビゲーションが消えてしまうようです。クロムで確認しました。まぁあまりウインドウサイズをスマホからPCがに変更するユーザーもいないとは思いますが、気になったのでお伝えさせていただきました。