JavaScriptでナビゲーション以外の場所をクリックしたらナビゲーションを閉じる

画面右上の丸いトグルボタンで、サイドナビゲーションの表示・非表示を切り替え。
ナビゲーション以外の部分をクリックすると、メニューは自動的に閉じる。
キーボードのESCキーでもメニューを閉じることができる。
classList.toggle() を使いコードを簡潔に。
contains() メソッドでクリック対象がメニュー内かを判定。
クリックでナビを閉じる機能の実装例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="author" content="X Media" />
<title>クリック対象外の領域をクリックした時の処理</title>
<style>
html {
--font-color: #7aabd6;
--hover-color: rgba(36, 97, 151, 0.2);
--background-color: #246197;
font-family: 'Courier New', Courier, monospace;
font-size: 15px;
}
*,
:before,
:after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
::selection {
color: var(--background-color);
background-color: var(--font-color);
}
body {
min-height: 100vh;
}
.toggle-btn {
position: fixed;
top: 10px;
right: 10px;
z-index: 5;
width: 40px;
height: 40px;
cursor: pointer;
transition: background-color 0.2s linear 0s;
border-radius: 100em;
}
.toggle-btn:hover {
background-color: var(--hover-color);
}
.toggle-btn:before,
.toggle-btn:after {
content: "";
display: block;
width: 50%;
height: 3px;
background-color: var(--background-color);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -5px);
transition: transform 0.4s cubic-bezier(.88, .22, .17, .98) 0s,
background-color 0.4s cubic-bezier(.88, .22, .17, .98) 0s;
}
.toggle-btn:after {
transform: translate(-50%, 2px);
}
.mobile-navigation {
color: var(--font-color);
width: 200px;
height: 100%;
position: fixed;
top: 0;
right: 0;
background-color: var(--background-color);
z-index: 4;
padding: 100px 20px 30px;
text-align: center;
transform: translateX(101%);
pointer-events: none;
opacity: 0;
transition: transform 0.3s cubic-bezier(.56, .15, .35, .99) 0s,
opacity 0s linear 0.3s,
pointer-events 0s linear 0.3s;
}
/* メニュー表示時のスタイル */
.show-mobile-navigation .mobile-navigation {
transform: translateX(0);
pointer-events: unset;
opacity: 1;
transition: transform 0.5s cubic-bezier(.56, .15, .35, .99) 0s,
opacity 0s linear 0s,
pointer-events 0s linear 0s;
}
/* トグルボタンの×表示 */
.show-mobile-navigation .toggle-btn:before,
.show-mobile-navigation .toggle-btn:after {
transform: translate(-50%, -50%) rotate(45deg);
background-color: var(--font-color);
}
.show-mobile-navigation .toggle-btn:after {
transform: translate(-50%, -50%) rotate(-45deg);
}
</style>
</head>
<body>
<div class="toggle-btn"></div>
<div class="mobile-navigation">ここにモバイルナビゲーションの内容が入ります。</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
const body = document.body;
const toggleBtn = document.querySelector(".toggle-btn");
const mobileNav = document.querySelector(".mobile-navigation");
// トグルボタンがクリックされたときの処理
toggleBtn.addEventListener("click", (event) => {
event.stopPropagation();
// メニューの表示・非表示を切り替える
body.classList.toggle("show-mobile-navigation");
});
// ドキュメント全体がクリックされたときの処理
document.addEventListener("click", (event) => {
const target = event.target;
// メニューが表示されていて、かつクリックがメニュー外かつトグルボタン外ならメニューを閉じる
if (
body.classList.contains("show-mobile-navigation") &&
!mobileNav.contains(target) &&
!toggleBtn.contains(target)
) {
body.classList.remove("show-mobile-navigation");
}
});
// ESCキーが押されたときの処理(メニューが表示されていれば閉じる)
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && body.classList.contains("show-mobile-navigation")) {
body.classList.remove("show-mobile-navigation");
}
});
});
</script>
</body>
</html>
コード解説
このコードは、モバイル向けのサイドナビゲーションメニューを実装しています。右上の丸いボタンをクリックすると、右側からナビゲーションがスライドして表示されます。ナビゲーション以外の領域をクリックすると自動でメニューが閉じ、ESCキーでもメニューを閉じることが可能です。
- HTML:ボタンとナビゲーションの構造を定義。
- CSS:ボタンやメニューのスタイル、表示・非表示時のアニメーションを制御。
- JavaScript:ボタンのクリックでメニュー表示切替、画面外クリックでメニュー非表示、ESCキー押下でメニュー閉じる挙動を制御。
注意点・補足
- ボタンのサイズやクリック可能範囲は適切に設定し、誤操作を防ぎましょう。
- メニューの中身が多い場合、スクロールや表示パフォーマンスの調整が必要になることがあります。
classList
とcontains()
は主要ブラウザで対応済みですが、古いブラウザでは動作確認が必要です。- イベントリスナーの解除処理は実装していません。動的に要素を追加・削除する場合は注意が必要です。
- ESCキーイベントはデフォルト動作を妨げないため、特定のケースでは別のショートカットに影響する可能性があります。
Web制作現場でよくある質問(FAQ)
Q1: なぜボタンクリック時にevent.stopPropagation()を使うのですか?
A1: クリックイベントのバブリングを防ぎ、ボタンをクリックした直後にドキュメントのクリックイベントが発火してメニューがすぐ閉じるのを防止します。
Q2: contains() メソッドの役割は?
A2: クリックされた要素がメニュー内またはボタン内かどうかを判定するために使用しています。
Q3: classList.toggle()を使う利点は?
A3: メニューの表示・非表示の切替処理が簡潔になり、コードの可読性と保守性が向上します。
Q4: ESCキーで閉じる機能はなぜ重要?
A4: キーボード操作での利便性やアクセシビリティ向上のため、視覚障害者などの利用も考慮しています。
まとめ
本コードはシンプルかつ実用的なモバイル向けサイドナビゲーションの実装例です。CSSのトランジションとJavaScriptのイベント管理を組み合わせることで、スムーズで直感的な操作を実現しています。現代のDOM APIを活用し、パフォーマンスと保守性のバランスも良好です。
より高度な機能や複雑なメニュー構造が必要な場合は、この基盤に機能追加する形で拡張が可能です。