はじめに
スマホ用ページなどでよく利用される、「ハンバーガーメニュー」をCSSのみで実装して見ます。
あくまで機能面の実装を目的としているので、デザイン面でのCSSは省略しています。
基本のHTML構造
<header class="header">
<h1><a href="index.html">TITLE</a></h1>
<div class="menu-trigger">
開く
</div>
<nav id="top-nav" class="nav-menu">
<ul>
<li><a href="index.html">HOME</a></li>
<li><a href="about.html">ABOUT</a></li>
<li><a href="contact.html">CONTACT</a></li>
</ul>
</nav>
</header>
ハンバーガーメニューの実装イメージ
「開く」ボタンと「閉じる」ボタンを押すことでメニューの開閉をする簡単な構造になります。
titleとmenuを両端に配置
.header{
display: flex;
justify-content: space-between;
}
flexboxを使って、左右両端に配置します。
nav-menuを右上に固定
.header{
position: relative;
}
.nav-menu{
position: absolute;
top: 0;
right: 0;
}
position:absoluteを使って位置を固定しています。
その際、基準となるheaderにposition: relativeを設定します。
メニュー開閉の仕組みを作る
メニュー開閉の仕組みは、cssのtarget属性にて実装します。
<header class="header">
<h1><a href="index.html">TITLE</a></h1>
<div class="menu-trigger">
<a href="#top-nav">開く</a>
</div>
<nav id="top-nav" class="nav-menu">
<a href="#!" class="menu-close">閉じる</a>
<ul>
<li><a href="index.html">HOME</a></li>
<li><a href="about.html">ABOUT</a></li>
<li><a href="contact.html">CONTACT</a></li>
</ul>
</nav>
</header>
aタブを用いて、対象のid属性を指定しています。
閉じるボタンの href="#!" は、ターゲットを外す目的で指定しています。
.nav-menu:not(:target){
}
.nav-menu:target{
}
非表示のスタイルを :not(:target)
表示スタイルを :target に記述します。
nav-menuを非表示にする
.nav-menu:not(:target){
opacity: 0;
visibility: hidden;
}
opacityで透明度を0に、visibility: hiddenで非表示にしています。
メニュー表示時、nav-menuを表示させる
.nav-menu:target{
opacity: 1;
visibility: visible;
}
opacityで透明度を1に、visibility: visibleで表示しています。
開閉時のフェードイン・アウト
.nav-menu:not(:target){
transition: 1s;
}
.nav-menu:target{
transition: 1s;
}
transitionでプロパティ変化の時間を指定しています。
閉じるボタンを右上に固定する
.menu-close{
position: absolute;
top: 0;
right: 0;
}
position:absoluteを使って位置を固定しています。
各要素の重なり具合を調整する
下から
- header(body)
- menu-trigger
- nav-menu
の順番で重なるようにz-indexを指定していきます
.menu-trigger{
position: relative;
z-index: 2;
}
.nav-menu{
z-index: 3;
background: white;
}
z-indexは、positionプロパティが設定されていないと適応されないため、position: relativeを追記しています。
nav-menuは、menu-triggerを隠すため、背景色をつけています。
ここまでのまとめ
<header class="header">
<h1><a href="index.html">TITLE</a></h1>
<div class="menu-trigger">
<a href="#top-nav">開く</a>
</div>
<nav id="top-nav" class="nav-menu">
<a href="#!" class="menu-close">閉じる</a>
<ul>
<li><a href="index.html">HOME</a></li>
<li><a href="about.html">ABOUT</a></li>
<li><a href="contact.html">CONTACT</a></li>
</ul>
</nav>
</header>
.header{
display: flex;
justify-content: space-between;
position: relative;
}
.nav-menu{
position: absolute;
top: 0;
right: 0;
z-index: 3;
background: white;
}
.nav-menu:not(:target){
opacity: 0;
visibility: hidden;
transition: 1s;
}
.nav-menu:target{
opacity: 1;
visibility: visible;
transition: 1s;
}
.menu-close{
position: absolute;
top: 0;
right: 0;
}
.menu-trigger{
position: relative;
z-index: 2;
}
レスポンシブ対応
PC版とスマホ版でCSSを切り替えます。
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head
cssにてメディアクエリを使用するため、headタグにてviewportを読み込みます。
PC版のスタイルは
.header{
display: flex;
justify-content: space-between;
position: relative;
}
.nav-menu{
display: block;
}
.nav-menu ul{
display: flex;
justify-content: space-between;
}
.nav-menu li{
padding-left: 10px;
}
.menu-close{
display: none;
}
.menu-trigger{
display: none;
}
で作られているものとして話を進めます。
メディアクエリの実装
PCとスマホのCSSで異なる点を記述してみます。
-- 共通 --
.header{
display: flex;
justify-content: space-between;
position: relative;
}
.nav-menu{
-- PC --
display: block;
-- スマホ --
position: absolute;
top: 0;
right: 0;
z-index: 3;
background: white;
}
-- PC --
.nav-menu ul{
display: flex;
justify-content: space-between;
}
.nav-menu li{
padding-left: 10px;
}
-- スマホ --
.nav-menu:not(:target){
opacity: 0;
visibility: hidden;
transition: 1s;
}
.nav-menu:target{
opacity: 1;
visibility: visible;
transition: 1s;
}
.menu-close{
-- PC --
display: none;
-- スマホ --
position: absolute;
top: 0;
right: 0;
}
.menu-trigger{
-- PC --
display: none;
-- スマホ --
position: relative;
z-index: 2;
}
今回はスマホ版をデフォルトとし、PC版をメディアクエリで変更していきます。
.header{
display: flex;
justify-content: space-between;
position: relative;
}
.nav-menu{
position: absolute;
top: 0;
right: 0;
z-index: 3;
background: white;
}
@media screen and (min-width: 1000px){
.nav-menu{
display: block;
}
}
@media screen and (min-width: 1000px){
.nav-menu ul{
display: flex;
justify-content: space-between;
}
}
@media screen and (min-width: 1000px){
.nav-menu li{
padding-left: 10px;
}
}
@media screen and (max-width: 1000px){
.nav-menu:not(:target){
opacity: 0;
visibility: hidden;
transition: 1s;
}
}
@media screen and (max-width: 1000px){
.nav-menu:target{
opacity: 1;
visibility: visible;
transition: 1s;
}
}
.menu-close{
position: absolute;
top: 0;
right: 0;
}
@media screen and (min-width: 1000px){
.menu-close{
display: none;
}
}
.menu-trigger{
position: relative;
z-index: 2;
}
@media screen and (min-width: 1000px){
.menu-trigger{
display: none;
}
}
pc版のスタイルに対して、@media screen and (min-width: 1000px)にてCSSを変更しています。
.nav-menu:not(:target), .nav-menu:target に関してはスマホ版のみのスタイルなので、@media screen and (max-width: 1000px) にて指定してあります。
以上にてレスポンシブ対応が完了しました。
ブレークポイントを増やす場合は、適宜追加してください。