CSSのみでレスポンシブWebデザイン対応のナビゲーションメニューを作成する


Webサイトのスマートフォンやタブレット端末に対応したメニューは、よくある3本線アイコンのハンバーガーメニューで、グローバルナビゲーションの表示・非表示を切り替える仕様で、主にCSSとJavaScriptまたはJavaScriptライブラリjQueryを併用して実装することが多いですが、CSSのみでも実装することができます。

Webページの動きとしては、JavaScriptの処理が走ることで若干処理速度が遅くなり、メニューの動作も遅くなります。
CSSのみで出来ることはなるべくCSSのみで実装すると良いでしょう。

今回は、CSSのみでスマートフォンやタブレット端末に対応したメニューを作成する方法についてご紹介します。
よくある3本線アイコンのハンバーガーメニューでもいいですが、ここではもう少しスタイリッシュな2本線のアイコンで実装していこうと思います。
(3本線にする場合は、線を一本足して微調整するくらいです)

CSSのみで実装するレスポンシブメニュー


CSSのみで実装するのには、クリックやタップを認識するため、input要素のチェックボックスやラベルを使用していきます。

まずはHTML。
メニューアイコンとグローバルナビゲーションは、header要素として構築していきます。
以下、サンプルコードになります。

HTML

<header>
  <input id="checkbox" type="checkbox">
  <label id="lineMenu" class="menu-check" for="checkbox">
    <span></span><span></span>
    <p>MENU</p>
  </label>
  <nav id="globalNav">
    <ul>
      <li><a href="">Menu 1</a></li>
      <li><a href="">Menu 2</a></li>
      <li><a href="">Menu 3</a></li>
      <li><a href="">Menu 4</a></li>
      <li><a href="">Menu 5</a></li>
      <li><a href="">Menu 6</a></li>
      <li><a href="">Menu 7</a></li>
      <li><a href="">Menu 8</a></li>
      <li><a href="">Menu 9</a></li>
      <li><a href="">Menu 10</a></li>
    </ul>
  </nav>
</header>

<main>

  <div id="mv">
    <h1>ABOVE THE FOLD</h1>
  </div>

  <section class="section-wrap">
    <div class="section-conts">
      <h2>HEADLINE</h2>
    </div>
  </section>

</main>



チェックボックスのinput要素にid「checkbox」を付与しておき、label要素のfor属性にチェックボックスのidを指定することで、label要素がチェックボックスの選択要素となります。
そしてlabel要素にて、spanタグやpタグでメニューアイコンに必要は要素を構築します。
グローバルナビゲーションは、navタグやul、liタグを使った通常の構造となります。

他、main要素には、簡単なWebページを構築しておきました。

続いてはCSS。
以下、サンプルコードになります。

CSS

header {
  position: fixed;
  top: 0;
  left: 0;
}

/*///// Hide Checkbox /////*/
#checkbox {
  opacity: 0;
  width: 0;
  height: 0;
}

/*///// lineMenu /////*/
#lineMenu {
  position: fixed;
  top: 1.5rem;
  right: 5rem;
  width: 36px;
  height: 16px;
  background: none;
  border: none;
  appearance: none;
  cursor: pointer;
}

#lineMenu,
#lineMenu span {
  z-index: 10;
}

#lineMenu span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #000;
  border-radius: 6px;
  transition: all 0.5s;
}

#lineMenu span:nth-of-type(1) {
  top: 0;
}

#lineMenu span:nth-of-type(2) {
  bottom: 0;
}

#lineMenu p {
  position: absolute;
  top: 50%;
  left: 2.6rem;
  transform: translateY(-50%);
  font-weight: bold;
}

#checkbox:checked ~ label span:nth-of-type(1) {
  transform: translateY(6px) rotate(-20deg);
}

#checkbox:checked ~ label span:nth-of-type(2) {
  transform: translateY(-6px) rotate(20deg);
}

/*///// Global Nav /////*/
#globalNav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  width: 100dvw;
  height: 100vh;
  height: 100dvh;
  background-color: rgb(255, 185, 0, .9);
  visibility: hidden;
  opacity: 0;
  transition: all 0.5s;
}

#checkbox:checked ~ #globalNav {
  visibility: visible;
  opacity: 1;
}

#globalNav ul {
  list-style: none;
  padding: 80px 4%;
  height: 100vh;
  height: 100dvh;
  overflow-y: scroll;
}

/*///// Global Nav and Webpage style /////*/
#globalNav li {
  margin: 0 auto 0.3rem;
  max-width: 800px;
  border-left: 6px solid #333;
}

#globalNav li a {
  display: block;
  padding: 1.5rem;
  background-color: rgba(255, 255, 255, .5);
  color: #333;
  text-decoration: none;
  transition: all 0.5s;
}

#globalNav li a:hover {
  background-color: rgba(255, 255, 255, .8);
  padding-left: 2.5rem;
}

#mv {
  height: 100vh;
  height: 100dvh;
  background-color: rgb(220, 220, 220);
  display: flex;
  justify-content: center;
  align-items: center;
}

.section-wrap {
  height: 100vh;
  height: 100dvh;
}

.section-conts {
  padding: 4%;
}

.section-conts h2 {
  text-align: center;
}



チェックボックスの表示は必要ないので、opacityプロパティや幅、高さを「0」として非表示にしておきます。
label要素(id「lineMenu」)からはメニューアイコンのスタイルになります。
label要素をpositionプロパティで右上に配置して、選択要素として幅と高さも指定しておきます。

label要素の子要素のspanタグは、background-colorと高さで線のデザインを作っています。
また、アニメーションできるようtransitionプロパティも指定しておきます。
擬似クラスnth-of-type()で、2つのspanタグ(線)の配置をlabel要素の高さの上下となるようにして2本線を表現します。
p要素の「MENU」は、2本線の右に垂直方向の中央になるよう配置させています。

そして今回のCSSのみで実装する部分の肝となるところが、擬似クラス「:checked」になります。
「:checked」を使うと、ラジオボタンやチェックボックス、オプションボタンなどの要素がチェックされているかを判別できます。
label要素がクリックやタップされたら、チェックボックスは非表示にしていますがチャックが入った状態となります。

input要素のチェックボックス(id「checkbox」)にチェックが入っている時のスタイルとして、隣接する兄弟要素のlabel要素のspanタグをtranslateY()関数で少し位置を調整したり、rotate()関数で少し回転させて傾けたりして、水平の2本線をバツのかたちに変化させています。
グローバルナビゲーションのid「globalNav」も、はじめはopacityプロパティを「0」として非表示にしていますが、チェックが入った時は「1」となり表示されるようになります。

グローバルナビゲーションもtransitionプロパティでアニメーションさせていますが、要素の透明度を指定するopacityプロパティだけでの表示・非表示はSEOの観点から影響を受けそうですので、displayプロパティやvisibilityプロパティで要素を非表示としておきたいですが、完全に要素を非表示とするdisplayプロパティはtransitionプロパティでは対応できないので、要素はあるけど非表示とすることができるvisibilityプロパティを使います。
ただ、表示のアニメーションまではvisibilityプロパティも対応しておりませんので、visibilityプロパティとopacityプロパティを併用していくことになります。

CSSのみで実装するレスポンシブメニュー



メニューを含むul要素には「overflow-y: scroll;」を指定しておいて、サブメニューなどを含めてコンテンツ量が多くなり画面の高さを超える場合を想定して、縦方向のスクロールできるようにしておくと良いでしょう。

その他の、globalNav以下のスタイルは、ご自身でデザインされるグローバルナビゲーションのスタイルを指定してください。

ちょっと実用的なレスポンシブメニュー


グローバルナビゲーションはスマートフォンやタブレット端末などだけの実装なのか、それともPCを含めすべてのデバイスで共通なのか、Webデザインによっても変わってきます。

コンテンツ量によってはナビゲーションリンクが多く並び、そのため窮屈だったり文字を小さくさせて見づらくなったりごちゃごちゃしたりと、なんでもリンクを並べればいいというものでもありません。
メインで必要な動線だけは表示させて残りは閉じておき、必要に応じてメニューを開いてもらう方がWebページがスッキリします。

先ほどのスマートフォン、タブレット端末用のメニューはそのまま活用しつつ、PCにシンプルなメニューを用意しておくと良いでしょう。

例えば以下のように、header要素の構造にPC用のメニュー(ul要素 id「pcNav」)を追加します。

HTML

<header>
  <ul id="pcNav">
    <li><a href="">Menu 1</a></li>
    <li><a href="">Menu 2</a></li>
    <li><a href="">Menu 3</a></li>
    <li><a href="">Menu 4</a></li>
  </ul>
  <input id="checkbox" type="checkbox">
  <label id="lineMenu" class="menu-check" for="checkbox">
    <span></span><span></span>
    <p>MENU</p>
  </label>
  <nav id="globalNav">
    <ul>
      <li><a href="">Menu 1</a></li>
      <li><a href="">Menu 2</a></li>
      <li><a href="">Menu 3</a></li>
      <li><a href="">Menu 4</a></li>
      <li><a href="">Menu 5</a></li>
      <li><a href="">Menu 6</a></li>
      <li><a href="">Menu 7</a></li>
      <li><a href="">Menu 8</a></li>
      <li><a href="">Menu 9</a></li>
      <li><a href="">Menu 10</a></li>
    </ul>
  </nav>
</header>



HTMLの構造に合わせて、先ほどのCSSから以下の内容を追加します。

CSS

header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  width: 100dvw;
  height: 4.2rem;
  background-color: rgba(255, 255, 255, .9);
  border-bottom: 1px solid #999;
}

#pcNav {
  display: none;
}


@media screen and (min-width:920px) {

  #pcNav {
    list-style: none;
    position: fixed;
    top: 1.2rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 3rem;
  }

  #pcNav a {
    text-decoration: none;
    color: #333;
    transition: all 0.5s;
  }

  #pcNav a:hover {
    color: #f00;
  }

}



header要素には、表示領域や背景などのスタイルを追加しました。
PC用のメニュー(id「pcNav」)は、スマートフォンやタブレット端末では必要ないので「display: none;」で非表示にしておき、メディアクエリで表示領域の幅がだいたいPCサイズの920pxより大きい(min-width:920px)時にdisplayプロパティをflexとして横並びのメニューとして表示させます。

CSSのみで実装する実用的なレスポンシブメニュー



PCはPC用のみのメニューとすると、表示されている情報が多くなりがちでごちゃごちゃしてしまいますが、PCもで表示するメニューはメインの動線のみとスッキリさせることで、コンテンツにも限られた表示領域でのデザインがしやすくなるのではないでしょうか。

以下、ここまでの実装の動きになります。
動画(3分50秒)

まとめ


CSSのみでスマートフォンやタブレット端末に対応したメニューを作成するポイントとしては、
input要素のチェックボックスを活用すること、そしてチェックボックスがチェックされているかをCSSで判別すること。
この2点になります。
JavaScriptのクリック判定の処理は、チェックボックスと擬似クラスの「:checked」で出来てしまうということです。

ここでは、2本線のメニューアイコンをサンプルに見てきましたが、線を1本増やして3本線にしたり、またCSSを駆使してオリジナルのアイコンメニューにしたりと、いろんなメニューのデザインを試してみてください。