モバイルファーストの時代では、スマートフォン向けのメニューの使いやすさが、ユーザー体験(UX)の向上に大きく貢献します。この記事では、スマートフォンメニューを作成する際に必要な、スクロール禁止とアンカーリンクでメニューが閉じる機能の実装方法を、初心者でもわかりやすく解説します。
モバイルメニューの基本構造
まず、シンプルなモバイルメニューをHTMLで作成します。メニューを開くボタンとメニュー内容を含め、リンクで指定した場所にスクロールする基本的な構造です。
<!-- メニューを開くボタン -->
<button class="menu-button">メニューを開く</button>
<!-- メニュー本体 -->
<div class="menu">
<button class="close-button">× 閉じる</button>
<nav>
<ul>
<li><a href="#contentA" class="menu-link">コンテンツA</a></li>
<li><a href="#contentB" class="menu-link">コンテンツB</a></li>
<li><a href="#contentC" class="menu-link">コンテンツC</a></li>
<li><a href="#contentD" class="menu-link">コンテンツD</a></li>
</ul>
</nav>
</div>
CSSでメニューのデザイン
次に、メニューを画面全体に表示させるためのCSSを追加します。モバイル画面にぴったりのデザインを適用します。
body {
font-family: Arial, sans-serif;
}
.menu-button {
position: fixed;
top: 20px;
left: 20px;
padding: 10px 20px;
background: #333;
color: #fff;
border: none;
cursor: pointer;
}
.menu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
color: white;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
transform: translateY(-100%);
transition: transform 0.3s ease-in-out;
}
.menu.open {
transform: translateY(0);
}
.close-button {
background: red;
color: white;
border: none;
padding: 10px;
margin-bottom: 20px;
cursor: pointer;
}
.menu nav ul {
list-style: none;
padding: 0;
text-align: center;
}
.menu nav ul li {
margin: 15px 0;
}
.menu nav ul li a {
color: white;
text-decoration: none;
font-size: 1.5rem;
}
JavaScriptでスクロール禁止とメニューの開閉を制御
ここでは、メニューを開いた時にスクロールを完全に停止し、メニュー内のリンクをクリックするとメニューが閉じるようにします。これを実現するためには、JavaScriptでスクロール禁止とイベント制御を行います。
const menu = document.querySelector('.menu');
const menuButton = document.querySelector('.menu-button');
const closeButton = document.querySelector('.close-button');
const menuLinks = document.querySelectorAll('.menu-link');
let scrollPosition = 0; // スクロール位置を保存する変数
function disableScroll() {
scrollPosition = window.scrollY; // 現在のスクロール位置を保存
document.body.style.overflow = 'hidden';
document.body.style.position = 'fixed';
document.body.style.width = '100%';
document.body.style.height = '100%';
document.body.style.top = `-${scrollPosition}px`;
document.addEventListener('touchmove', preventDefault, { passive: false });
document.addEventListener('wheel', preventDefault, { passive: false });
}
function enableScroll() {
document.body.style.removeProperty('overflow');
document.body.style.removeProperty('position');
document.body.style.removeProperty('width');
document.body.style.removeProperty('height');
document.body.style.removeProperty('top');
window.scrollTo(0, scrollPosition); // 保存したスクロール位置に戻す
document.removeEventListener('touchmove', preventDefault);
document.removeEventListener('wheel', preventDefault);
}
function preventDefault(event) {
event.preventDefault();
}
menuButton.addEventListener('click', () => {
menu.classList.add('open');
disableScroll();
});
closeButton.addEventListener('click', () => {
menu.classList.remove('open');
enableScroll();
});
// メニュー内のリンクをクリックしたら閉じる
menuLinks.forEach(link => {
link.addEventListener('click', (event) => {
menu.classList.remove('open');
enableScroll();
});
});
動作の仕組み
現在のスクロール位置を保存
メニューが開かれるとき、現在のスクロール位置を保存します。これにより、メニューを閉じた後、スクロール位置が元の位置に戻ります。
scrollPosition = window.scrollY;
position: fixed;
を適用してスクロールを完全に停止
メニューが開くと、document.body.style.position = 'fixed';
により、ページ全体が固定され、スクロールを防ぎます。
スクロール関連のイベントをpreventDefault()
で阻止touchmove
やwheel
などのスクロールイベントをpreventDefault()
で阻止し、ユーザーがスクロールできないようにします。
メニューを閉じたらスクロール位置を元に戻す
メニューを閉じる際に、window.scrollTo()
で保存したスクロール位置にページを戻します。
iOS特有のバグとその回避方法
iOSでは、position: fixed
を使った際にスクロールが正しく機能せず、画面がずれる問題が発生することがあります。そこで、今回は以下の方法でiOS特有のバグを回避しています。
どちらを使うべきか?
この方法を使うことで、iOSでもバグを回避し、Androidでも確実に動作します。スクロール位置を記憶することで、メニューを閉じても元のスクロール位置に戻り、スムーズなユーザー体験が提供できます。
サンプル
See the Pen Side-menu-button by kasasagi_kmnmc (@kasasagi_kmnmc) on CodePen.
まとめ
この記事では、モバイルメニューの作成方法と、スクロール禁止およびアンカーリンクでメニューが閉じる機能の実装方法を解説しました。iOSでもバグを回避したスクロール制御を取り入れることで、どのデバイスでも安定して動作します。
初心者の方でも理解しやすいように、実装方法とそのメリットについても説明しました。ぜひ、この記事を参考にして、自分のWebサイトでスマートフォン向けの快適なメニューを作成してみてください。