レスポンシブWebデザインに対応したメニューの作り方【追記あり】

レスポンシブに対応した横メニューを作る機会があったので、せっかくですし作り方を紹介したいと思います。お役に立てばうれしいです。

responsive-menu0.png
【追記 2014.03.19】

元々のタイトルは「レスポンシブWebデザインに対応した横メニューの作り方」でしたが、よく考えるとスマホ対応になったら縦メニューになりますのでタイトルを変更しました。

できあがりはこちらのサンプルをご覧ください。

それでは作り方を解説していきます。

HTML

まずはHTMLです。

id名「toggle」の部分は横幅が480px以下の場合に表示するボタンです。481px以上の場合表示させません。その他はごく普通の横メニューです。

CSS

続いてCSSです。まずは全体を載せます。

#menu{
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0;
}
#menu li{
  display: block;
  float: left;
  width: 12.5%;
  margin: 0;
  padding: 0; }
#menu li a{
  display: block;
  padding: 12px 0 10px;
  background: #333;
  color: #fff;
  text-align: center;
  text-decoration: none;
}
#menu li a:hover{
  background: #444;
}
#toggle{ 
 display: none;
}
@media only screen and (max-width: 768px) {
    #menu li{
    width: 25%;
    border-bottom: 1px solid #444;
  }
}
@media only screen and (max-width: 480px) {
  #menu{
    display: none;
  }
  #menu li{
    width: 100%;
  }
  #toggle{
    display: block;
    position: relative;
    width: 100%;
    background: #222;
  }
  #toggle a{
    display: block;
    position: relative;
    padding: 12px 0 10px;
    border-bottom: 1px solid #444;
    color: #fff;
    text-align: center;
    text-decoration: none;
  }
  #toggle:before{
    display: block;
    content: "";
    position: absolute;
    top: 50%;
    left: 10px;
    width: 20px;
    height: 20px;
    margin-top: -10px;
    background: #fff;
  }
  #toggle a:before, #toggle a:after{
    display: block;
    content: "";
    position: absolute;
    top: 50%;
    left: 10px;
    width: 20px;
    height: 4px;
    background: #222;
  }
  #toggle a:before{
    margin-top: -6px;
  }
  #toggle a:after{
    margin-top: 2px;
  }
}

では、部分ごとで解説していきます。

最初の状態
responsive-menu.png

CSSはごく普通のメニューですので問題ないと思います。今回は横に8つ並ぶメニューですので、1つの横幅は12.5%にしています。

#menu{
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0;
}
#menu li{
  display: block;
  float: left;
  width: 12.5%;
  margin: 0;
  padding: 0; }
#menu li a{
  display: block;
  padding: 12px 0 10px;
  background: #333;
  color: #fff;
  text-align: center;
  text-decoration: none;
}
#menu li a:hover{
  background: #444;
}
#toggle{ 
 display: none;
}

全体の横幅は100%ですが、1920pxなど大きなディスプレイで100%になると広すぎて逆に見にくいので、max-width: 960px;を指定しています。

最近はモバイルファーストで小さいディスプレイから設計する場合も多いようですが、IE8以下はメディアクエリに対応していないこともあり、今はまだPCから考える方がいいかと個人的には考えています。

もちろんIE8以下でもメディアクエリを有効にする方法はあります。下のコードを追加するだけです。

768px以下の場合
responsive-menu2.png

続いて、タブレットなどを想定した768px以下のディスプレイで見た場合のスタイルです。

@media only screen and (max-width: 768px) {
    #menu li{
    width: 25%;
    border-bottom: 1px solid #444;
  }
}

メニューの幅を12.5%から25%へと倍にすることで、1列から2列になります。上下の区切りが分かるように下線を引いています。

横線を引いてもいいかもしれません。横線を引く場合は「box-sizing: border-box」を指定する必要があります。指定しないと3つで折り返してしまいます。

「box-sizing: border-box」については先日書いたこの記事をご参考に。

480px以下の場合
responsive-menu3.png

最後はスマホなど480px以下のディスプレイで見た場合のスタイルです。ここでガラッと変わります。初期状態ではメニューの内容は表示されず、「menu」と書かれたボタンのみ表示されています。その「menu」をクリックするとメニューの内容がスライドして現れます。

クリックしてメニューが現れる仕組みはjQueryで実装します。コードはCSSの後で紹介しています。

@media only screen and (max-width: 480px) {
  #menu{
    display: none;
  }
  #menu li{
    width: 100%;
  }

#menuの表示をいったん消して、メニュー1つの幅を100%にします。

  #toggle{
    display: block;
    position: relative;
    width: 100%;
    background: #222;
  }
  #toggle a{
    display: block;
    position: relative;
    padding: 12px 0 10px;
    border-bottom: 1px solid #444;
    color: #fff;
    text-align: center;
    text-decoration: none;
  }

いったん消したメニューを開くためのボタンを作ります。最初に消していた#toggleをここで表示するようにします。後で指定する擬似要素の基準となるため、position: relativeを指定します。

最後に左のアイコンです。画像を使ってもいいですが、CSSで表現できるものはCSSでおこないたいです。

  #toggle:before{
    display: block;
    content: "";
    position: absolute;
    top: 50%;
    left: 10px;
    width: 20px;
    height: 20px;
    margin-top: -10px;
    background: #fff;
  }
  #toggle a:before, #toggle a:after{
    display: block;
    content: "";
    position: absolute;
    top: 50%;
    left: 10px;
    width: 20px;
    height: 4px;
    background: #222;
  }
  #toggle a:before{
    margin-top: -6px;
  }
  #toggle a:after{
    margin-top: 2px;
  }
}

ちょっと分かりにくいかもしれませんのでボタンの構造を画像にしてみました。

responsive-menu4.png

白い正方形の上に黒い長方形を2つ乗せて3本線を表現しています。

この3つの要素はすべて擬似要素で作られています。この辺の使い方は慣れるまで難しいかもしれませんが、使い慣れるとCSSの幅がぐっと広がります。

では、縦の位置の調整について、ボタンの部分をもっと拡大して解説します。

responsive-menu6.png

top: 50%;を指定することで、擬似要素の上の位置が画像の点線部分になります。

白い正方形にあたる「#toggle:before」の場合は高さ20pxの半分にあたる10pxを「margin-top: -10px」で上げることで上下中央に表示されます。

続いて、白い正方形を区切る2つの黒い長方形について、「#toggle a:before」は真ん中の太い点線部分から6px上げて(上の点線)、「#toggle a:after」は点線部から2px下げて(下の点線)表示しています。

jQuery

#toggleを押してメニューを開く仕組みはjQueryで実装します。jQueryファイルは各自指定しておいてください。

【追記 2014.3.19】

コメント等で、スマホ対応の表示のときにメニューを開いて閉じてからウインドウサイズを大きくするとメニューが消えてしまうとのご指摘をいただきました。

実際使う場合ころころディスプレイサイズを変えることもないので対応しなかったのですが、iPhoneの縦から横にしたときなどはこの現象が起きてしまいますので対応しました。具体的には6行目以降が追加されています。

画面サイズが変わって480pxより広くなると「#menu」が表示され、480px以下の場合は表示されなくなります。

ご指摘いただいた皆様、ありがとうございました。

【追記 2017.1.15】

iosの場合、スクロールした際にresizeイベントが発生します。そのため、スクロールした際に開いたメニューが閉じてしまいます。

今回、下記の赤字の部分を削除することで対応しています。

今更で申し訳ございませんがよろしくお願いします。

    if(win > p){
      $("#menu").show();
    } else {
      $("#menu").hide();
    }

ということで、以下のようになっています。

$(function(){
  $("#toggle").click(function(){
    $("#menu").slideToggle();
    return false;
  });
  $(window).resize(function(){
    var win = $(window).width();
    var p = 480;
    if(win > p){
      $("#menu").show();
    }
  });
});

#toggleをクリックするたびに#menuがスライドして開閉します。jQueryを知らない方でもイメージできるようなシンプルなコードです。この辺がjQueryの親しみやすさかなと思ったりしています。

まとめ

ということで、レスポンシブにデザインする際に使えそうな横メニューの作り方を解説しました。

今回は8個のメニューということで、3パターンに変形するようにしました。これが7つになると2列にはしにくいので、今回のようにはいかないと思います。かといってあまり早い段階で縦1列にするとメニューの幅が広くなりすぎてスペースの無駄使いになります。

どのポイントでどのように変形させるかは、メニューの数によって様々だと思います。

また、メニューと直接関係ないかもしれませんが、3本線の作り方は役に立ちますので、ぜひ覚えていってください。

フィードやTwitterで最新情報をチェック
follow us in feedly
この記事に付いているタグの最新記事一覧
loading...
コメント
こんにちは。いつも大変参考になる記事をありがとうございます!
スマホサイズのときに一度メニューを開いて、閉じて、その後ウインドウサイズを広げると、ナビゲーションが消えてしまうようです。クロムで確認しました。まぁあまりウインドウサイズをスマホからPCがに変更するユーザーもいないとは思いますが、気になったのでお伝えさせていただきました。
【2014/03/19 13:31】 | - #- | [edit]
コメントありがとうございます。

ご指摘の通りスマホ対応の表示のときにメニューを閉じてから
ウインドウサイズを大きくするとメニューが消えてしまいます。

実際使う場合ころころディスプレイサイズを変えることもないので
対応しなかったのですが、はてなブックマークのコメントでも
ご指摘いただいていますので、応急的に対応しました。

もう少し調査して問題なければ追記したいと思います。
【2014/03/19 18:03】 | 管理人 #E2ywrYdA | [edit]
はじめまして。
いつも参考になる記事をありがとうございます。

今回紹介しているメニューの作り方を利用したいと思っておりますが、
ライセンスはどのようになっておりますでしょうか?
商用サイトでの利用を考えております。

また、利用可能な場合は著作権表記などは必要でしょうか?

何卒よろしくお願い致します。
【2014/07/02 17:36】 | MOTO #- | [edit]
MOTOさん

コメントありがとうございます。

特にライセンスは定めていませんが、
商用サイトであってもご自由に使っていただいて大丈夫です。

解説を丸々使われたりすれば困りますが、
出来上がりのメニューを実装する分にはまったく構いません。

その際特に著作権表記などは必要ありません。

今後ともよろしくお願いします。
【2014/07/03 07:08】 | 管理人 #E2ywrYdA | [edit]
はじめまして。
こちらのレスポンシブ対応メニューを使わせ頂きました!
とても簡単に実装できてとても助かっております。

一つこれがほしいなーと思うことがあり、コメントさせて頂きました。

スマホサイズ時にメニューを押しページ移動をした際、
メニューが閉じないままなので、これが閉じるといいなーと思いました。

もしご対応頂けたら嬉しいです!
よろしくお願い致します。
【2014/11/13 00:31】 | SSS #- | [edit]
こんばんは。

いつも参考にさせて頂いております。

この度、こちらの記事を参考にページを作成したのですが、
管理人様と作成の順番の違うスマホ→タブレット→PCで作成しましたところ、
幅480前後でメニューが消える現象が起こっております。

使用したブラウザはchromeです。

実際にスマホで使用の際は問題の方ございませんが、気になったので質問させて頂きました。

最初はスマホ、
@media screen and (min-width: 481px)
でタブレットなど、
@media screen and (min-width: 769px)
でPCという風に作成しております。

上記の場合、jQueryの内容の変更が必要でしょうか?

今からCSSを全て書き換えるのは少々骨が折れますので、
お時間ありましたらお教え頂けると幸いです。
【2014/11/14 22:16】 | JJ #- | [edit]
<div id="menu-box">の"menu-box"についての

CSSがどこにかかれていますでしょうか?


<ul id="menu">の "menu"についてしか書いてありませんけど
これは何か意味があるのでしょうか?
【2015/03/24 17:58】 | かたやま #HfMzn2gY | [edit]
かたやま さん

#menu-boxについては特にCSSで指定していません。

#toggleと#menuがセットになっているため、
セットになっていることが分かるよう、
両方の親となる#menu-boxを作っています。
【2015/03/26 18:34】 | 管理人 #E2ywrYdA | [edit]
参考にさせていただきました!
上記のメニューと一緒に、高さを揃えるjs(linehightやjquery.tileなど)を使用したいのですが、
なせか「display: none;」を指定しているせいか、
高さが揃わないです・・・

両方正常に使用するためには、どの箇所を修正するとよろしいでしょうか?
お手すきの際に、ぜひご教授いただけますと助かります!
【2015/06/08 11:55】 | オカリナ #iqj3wRFw | [edit]
ハンバーガーを右に持ってくる方法を教えていただけませんか。
よろしくお願いいたします。
【2016/01/18 23:22】 | Tenz #tHX44QXM | [edit]
他の方も指摘されているように、(480px付近)あたりで一度ヘッダーメニューが消えます。
IE11、FireFox50.1.0またスマホでは、iOS10(iPhone5s/6s)で縦から横に回転させた時に現象を確認できました。
これはjQueryというよりメディアクエリーの問題な気もします。

なお、iOS8以降に見られる画面をスライドさせた際のアドレスバー消滅に連動した、resizeのリセットに起因するメニューが消えてしまう問題は自力で解決しました。
その後からはローカルでは消えないのですがサーバに上げると消えるというよりややこしい問題になってしまいました。

ここで紹介されているメニューはカスタマイズ性も高くまた、シンプルで記述も短いというメリットだらけのメニューです。
これ以上の優秀なメニューはないと思います。
なので、素人ながらこのメニューがより完成度の高いものになって下さる事を心から祈っております。
【2016/11/25 03:18】 | nanasu #GCA3nAmE | [edit]
メニュー実装させて頂きました。本当にありがとうございました。
ちょっと困った点が1点ありますのでご相談させてください。
Headerにメニューを置きました。
スマホサイズになったときに左のメニューを消し、
右側のコンテンツだけが表示されるようにしました。
ところが、メニューがコンテンツの上部にかぶってしまい
一部が見えなくなる状態です。
<div class="clear"></div>をコンテンツの最初に
入れてみたりしましたが、段落ちしてしまいます。

素人がレスポンシブに挑戦しましたので
何か根本的な間違いをしているのかもしれません。
教えて頂ければ嬉しいです。
【2017/02/14 10:09】 | キクミ #GWRdFx3s | [edit]
大変参考になる記事をありがとうございます。
とてもきれいなのでこちらがさらにドロップダウンメニューになる方法も是非アップして頂きたいです!
【2017/10/04 15:31】 | かとう #- | [edit]









※コメントはご意見ご感想や間違いのご指摘等にしていただけますようお願いいたします。コメントを確認する時間がなく、技術的なご質問をいただいても答えできません。申し訳ございませんがご理解のほどお願いいたします。

Recent Entry
Popular Entry
  • このエントリーをはてなブックマークに追加