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

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キー押下でメニュー閉じる挙動を制御。

注意点・補足

  • ボタンのサイズやクリック可能範囲は適切に設定し、誤操作を防ぎましょう。
  • メニューの中身が多い場合、スクロールや表示パフォーマンスの調整が必要になることがあります。
  • classListcontains() は主要ブラウザで対応済みですが、古いブラウザでは動作確認が必要です。
  • イベントリスナーの解除処理は実装していません。動的に要素を追加・削除する場合は注意が必要です。
  • ESCキーイベントはデフォルト動作を妨げないため、特定のケースでは別のショートカットに影響する可能性があります。

Web制作現場でよくある質問(FAQ)

Q1: なぜボタンクリック時にevent.stopPropagation()を使うのですか?

A1: クリックイベントのバブリングを防ぎ、ボタンをクリックした直後にドキュメントのクリックイベントが発火してメニューがすぐ閉じるのを防止します。

Q2: contains() メソッドの役割は?

A2: クリックされた要素がメニュー内またはボタン内かどうかを判定するために使用しています。

Q3: classList.toggle()を使う利点は?

A3: メニューの表示・非表示の切替処理が簡潔になり、コードの可読性と保守性が向上します。

Q4: ESCキーで閉じる機能はなぜ重要?

A4: キーボード操作での利便性やアクセシビリティ向上のため、視覚障害者などの利用も考慮しています。


まとめ

本コードはシンプルかつ実用的なモバイル向けサイドナビゲーションの実装例です。CSSのトランジションとJavaScriptのイベント管理を組み合わせることで、スムーズで直感的な操作を実現しています。現代のDOM APIを活用し、パフォーマンスと保守性のバランスも良好です。

より高度な機能や複雑なメニュー構造が必要な場合は、この基盤に機能追加する形で拡張が可能です。

関連記事
【SEO基礎】rel=”nofollow”とは?リンクの評価をコントロールするHTML属性を解説
SEO対策に欠かせない「rel="nofollow"」の意味と使い方を解説。広告やユーザー投稿に適切なrel属性を設定し、検索エンジンとの正しい関係を築きましょう。
qqplus
qqplus
6日前
【SEO基礎】rel=”nofollow”とは?リンクの評価をコントロールするHTML属性を解説
JavaScriptでURL(パス)からファイル名を取得する
window.location.pathname でURLのパス部分を取得。 lastIndexOf('/') で最後のスラッシュ位置を検出。 substring でスラッシュの次から最後までを切り出し、ファイル名を抽出。
Details
Details
26日前
JavaScriptでURL(パス)からファイル名を取得する
SCSSの @for ループ(ループ文)
SCSSの @for ループ
Beefy Guy
Beefy Guy
1ヶ月前
SCSSの @for ループ(ループ文)
フッターのJavaScriptは画像読み込みに影響する?ブラウザの読み込み順と最適化の基本
はじめに Webサイトの表示速度や操作感は、単にコンテンツの量や見た目だけでなく、ブラウザがリソースをどのように読み込むかによっても大きく左右されます。特にJavaScriptや画像の読み込み順序、そしてそれらがどのように相互作用しているか […]
解構人
解構人
4日前
フッターのJavaScriptは画像読み込みに影響する?ブラウザの読み込み順と最適化の基本
scroll-behaviorで平滑スクロール、一行でいけるんだ
一般的に、アンカーリンクをスムーズにスクロールさせる時、JavaScriptやjQueryで実装することが多いです。例えば、 でも実は、CSSだけでもできるんです。そのためのプロパティがこちら: これを書くだけで、リンクをクリックした時にス […]
メモ・ノートスケ
メモ・ノートスケ
25日前
scroll-behaviorで平滑スクロール、一行でいけるんだ
スクロール位置でアニメ発火!jQueryで特定クラスを追加する方法
jQuery を使ってページのスクロールイベントを監視し、特定の位置に到達した際に要素へ指定したクラスを追加することで、CSS アニメーションを利用した「要素の登場アニメーション」を実現できます。これはウェブデザインでよく使われる手法で、ページのインタラクション体験や視覚的な魅力を高める効果があります。
Details
Details
16日前
スクロール位置でアニメ発火!jQueryで特定クラスを追加する方法
jQuery Sortableがスマホなどのタッチスクリーンで使えない場合の対処法
モバイル端末でのクリックイベントとの競合を避けるため、タップ操作には click より touchstart を使うことを推奨。 jQuery UI のバージョンによっては、内部構造が異なる場合があるため、導入時はテストを行うこと。
Details
Details
25日前
jQuery Sortableがスマホなどのタッチスクリーンで使えない場合の対処法
相対パスと絶対パスの使い方
相対パスは、モジュールやディレクトリ内のローカルな参照に適しており、柔軟性があります。一方、絶対パスはウェブサイト全体で共通のリソース(CSS、画像、CDNなど)を参照する際に便利です。両者を理解して使い分けることで、パスのエラーや読み込み不具合を防げます。
Details
Details
18日前
相対パスと絶対パスの使い方
日本語用WebサイトのCSSフォント設定(日本語フォント/游ゴシック/游明朝)
日本語フォントはOSにより異なるため、複数のフォントを優先順に指定する。 "Yu Gothic"や"Yu Mincho"はモダンな日本語フォントでWindows 8.1以降に搭載。 "ヒラギノ角ゴ"や"ヒラギノ明朝"はmacOS向けで、高品質。 "メイリオ"や"MS 明朝"などは古いWindows環境にも対応。 ゴシック体はカジュアル・読みやすさ重視、明朝体はフォーマル・高級感重視に適している。
Details
Details
17日前
日本語用WebサイトのCSSフォント設定(日本語フォント/游ゴシック/游明朝)
和暦から西暦変換ツール
このツールは、日本の元号(和暦)と西暦を相互に変換できるシンプルな変換ツールです。「昭和64年は何年?」「2025年は令和何年?」といった場面で、すぐに答えがわかります。 履歴書の作成、行政手続き、年齢計算、歴史的資料の読み解きなどにご活用 […]
X SIGHT 編集部
X SIGHT 編集部
5日前
和暦から西暦変換ツール
【2025年6月最新版】TIOBEインデックスで見る人気プログラミング言語ランキングとは?
2025年6月最新版のTIOBEインデックスから、今人気のプログラミング言語を解説。Python、C、C++、Javaなどの注目度や、インデックスの活用方法も紹介します。
解構人
解構人
10日前
【2025年6月最新版】TIOBEインデックスで見る人気プログラミング言語ランキングとは?
JavaScript を使って通貨形式を数値に変換する
JavaScriptの正規表現を利用し、通貨表記に含まれる無効な記号を取り除くことで、簡単に通貨文字列を数値に変換できます。これにより、数値計算や金額比較などが容易になります。
Details
Details
26日前
JavaScript を使って通貨形式を数値に変換する
第1回:ウェブにおける色の基礎(2025年最新版)
ウェブデザインの基礎「色」について、2025年最新トレンドやアクセシビリティ・ダークモード対応まで、実務ですぐ使えるCSS色指定方法を分かりやすく解説。初心者から現場のデザイナーまで必見のカラーマネジメント入門ガイド。
X SIGHT 編集部
X SIGHT 編集部
29日前
CSSで等間隔配置を実現:1行に複数または複数行に配置
CSSでは、特にレスポンシブデザインにおいて、複数の要素を等間隔に配置する必要があります。列数や間隔を動的に制御することで、柔軟なレイアウトが実現可能です。この記事では、FlexboxとGridの2つの方法を使って、1行に複数のアイテムを等間隔に配置する方法を紹介します。コード内の変数(列数や間隔)を調整することで、1行に表示するアイテム数やその間隔を簡単に管理でき、レイアウト調整が容易になり、開発効率が大幅に向上します。
Beefy Guy
Beefy Guy
1日前
CSSで等間隔配置を実現:1行に複数または複数行に配置
IT業界の初心者が知っておくべきの用語(2025版)
新しいテクノロジーについて話すとき、時々自分がみんなのペースについていけないと感じることはありませんか?あるいは、その業界にいるのに、自分はまだ十分ではないと感じ、多くの専門用語を理解しなければならないこともあるでしょう。
Details
Details
9日前
IT業界の初心者が知っておくべきの用語(2025版)