スマホでよく見るハンバーガーメニュー。
メニューが長いと開いた時に画面下が見切れて、スクロールが必要になってくる。
でも、メニューをスクロールしようとすると背景もスクロールされてしまうことありませんか?
スクロールバーが2重に見えたり、
スマホだと上手くメニューをスクロール(スワップ)できなかったり。。めっちゃイラ(`´)
こちら、cssとjavascriptで解決します!
結論
メニューが開いてる時だけ背景を固定することで、メニューのみをスクロールすることができます。
結果のプレビューはこちら↓ または別ウインドウで確認できます。(ダウンロード可)
プレビュー
そしてソースはコチラ↓
とその前に、
長いので先にポイントを説明すると
- メニューの開閉は、js不要でcssのみで実装。2行目にあるチェックボックスを使います。
- 「メニューが開いてる時は背景を固定する」の設定が、209行目からのjavascript。
チェックボックスにチェックがあるかどうかの判定から、bodyタグにスタイルのoverflowを使ってhidden/autoをあてることで、背景の固定/解除を切り替えてます。 - 149行目では、メニューが開いた時はそのメニュー外枠の高さを明示すること!
でないと思ったようにスクロールできない場合があります。画面いっぱいにメニューを開きたい場合はheight: 100vhで良いと思います。
<body>
<input type="checkbox" id="menuBtnCheck" />
<div class="wrapper">
<header class="g-header">
<div class="g-header-inner">
<div class="header-logo-wrap">
<h1 class="header-logo">ハンバーガーメニュー</h1>
</div> <!-- .header-logo-wrap -->
<div type="button" id="navBtn">
<label for="menuBtnCheck" id="menuBar" class="btn-open">
<span></span>
<span></span>
<span></span>
</label>
</div> <!-- #navBtn -->
<div id="navigation" class="overlay">
<nav>
<ul>
<li>メニュー1</li>
<li>メニュー2</li>
<li>メニュー3</li>
<li>メニュー4</li>
<li>メニュー5</li>
</ul>
</nav>
<div class="menu_bk-1">
<p>ナビメニューの下部要素1</p>
</div>
<div class="menu_bk-2">
<p>ナビメニューの下部要素2</p>
</div>
</div><!-- #navigation -->
</div><!-- .g-header-inner -->
</header>
<main>
<p>メインコンテンツ</p>
</main>
</div><!-- .wrapper -->
<footer>
<p>フッター</p>
</footer>
</body>
<style>
/* ヘッダー */
.header-logo {
font-size: 1.5em;
}
.g-header {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 35px);
z-index: 99;
padding: 0 10px;
transition: .2s;
}
.header-logo-wrap {
z-index: 999;
}
/* メニューリンクの装飾 */
nav ul li {
cursor: pointer;
transition: .2s;
}
nav ul li:hover {
opacity: .8;
background: #eee;
}
/* メニューバー */
#menuBtnCheck {
display: none;
}
#navBtn {
position: absolute;
display: block;
right: 10px;
top: 0;
z-index: 999;
}
#menuBar {
display: inline-block;
text-decoration: none;
position: relative;
width: 60px;
height: 60px;
opacity: 1;
cursor: pointer;
z-index: 999;
}
#menuBar > span {
position: absolute;
transition-duration: 0.2s;
background: #534340;
height: 2px;
}
#menuBar > span {
left: 16px;
right: 15px;
}
#menuBar > span:nth-child(1) {
top: 20px;
}
#menuBar > span:nth-child(2) {
top: 30px;
}
#menuBar > span:nth-child(3) {
top: 40px;
}
/* メニューが開いた時 */
#menuBtnCheck:checked ~ .wrapper #menuBar > span:nth-child(1) {
top: 30px;
position: absolute;
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
#menuBtnCheck:checked ~ .wrapper #menuBar > span:nth-child(2) {
display: none;
}
#menuBtnCheck:checked ~ .wrapper #menuBar > span:nth-child(3) {
position: absolute;
top: 30px;
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
/* オーバーレイ */
.overlay {
display: none;
}
#menuBtnCheck:checked ~ .wrapper .overlay {
position: fixed;
top: 68px;
left: 0;
right: 0;
height: 100vh; /* 高さを指定するのがポイント! でないとoverflowが効かない。 */
z-index: 99;
display: block;
overflow: auto;
box-shadow: 3px 3px 3px #e4e4e4;
margin: 0;
padding: 0;
background: rgba(255,255,255, .75);
}
/* 独自の装飾 */
body {
color: #534340;
}
header {
background: #F4FCD9;
}
main {
height: 90vh;
background: #C5D8A4;
box-sizing: border-box;
}
main p {
text-align: center;
padding: 45vh 2em 0;
font-weight: bold;
}
footer {
text-align: center;
height: 30vh;
background: #BB9981;
box-sizing: border-box;
}
footer p {
padding: 15vh 2em 0;
font-weight: bold;
color: #fff;
}
.menu_bk-1 {
display: block;
height: 500px;
background: #e79f94;
color: #fff;
padding: 250px 0 0;
font-weight: bold;
text-align: center;
box-sizing: border-box;
}
.menu_bk-2 {
display: block;
height: 500px;
background: #4e3a3a;
color: #fff;
padding: 250px 0 0;
font-weight: bold;
text-align: center;
box-sizing: border-box;
}
</style>
<script>
// bodyへのoverflow設定:ここで背景のスクロールを固定する。
var menuBtnCheck = document.getElementById('menuBtnCheck');
var menuBar = document.getElementById('menuBar');
var body = document.getElementsByTagName('body');
menuBar.onclick = function() { // メニューバーをクリックした時
if (menuBtnCheck.checked) {
document.body.style.overflow = 'auto';
} else {
document.body.style.overflow = 'hidden';
}
}
</script>
以上です!
あるサイトの公開後に実機のスマホで確認すると、
ハンバーガーメニューの内容が、画面から見切れててもスクロールができない。2重にスクロールバーが見えて変!という現象が起こりました。
bodyにoverflow:hiddenへの解決にいたるまで時間がかかりとても焦ったので、もし同じ現象に出くわした方はご参考までに。