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を活用し、パフォーマンスと保守性のバランスも良好です。

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

関連記事
日本語用WebサイトのCSSフォント設定(日本語フォント/游ゴシック/游明朝)
日本語フォントはOSにより異なるため、複数のフォントを優先順に指定する。 "Yu Gothic"や"Yu Mincho"はモダンな日本語フォントでWindows 8.1以降に搭載。 "ヒラギノ角ゴ"や"ヒラギノ明朝"はmacOS向けで、高品質。 "メイリオ"や"MS 明朝"などは古いWindows環境にも対応。 ゴシック体はカジュアル・読みやすさ重視、明朝体はフォーマル・高級感重視に適している。
Details
Details
5ヶ月前
日本語用WebサイトのCSSフォント設定(日本語フォント/游ゴシック/游明朝)
CSSによる絶対中央寄せ
実用性が高い方法順で7種類の実装方法を紹介 最も推奨されるのは Flexbox と Grid transform を使う方法はどんな要素にも応用可能 line-height や table-cell は特定用途向け JavaScript による制御も紹介されている
Details
Details
5ヶ月前
CSSによる絶対中央寄せ
【CSSテクニック】:not()セレクタで階層を跨いだ除外を実現
:not()疑似クラスはCSSでの除外指定に便利ですが、親要素や階層関係に対しては思わぬ制約があります。本記事では、WordPressの投稿構造を例に、インラインコードとコードブロックを正確に区別するためのセレクタ設計を解説します。
無敵の小さな蚊
無敵の小さな蚊
5ヶ月前
【CSSテクニック】:not()セレクタで階層を跨いだ除外を実現
IT業界の初心者が知っておくべきの用語(2025版)
新しいテクノロジーについて話すとき、時々自分がみんなのペースについていけないと感じることはありませんか?あるいは、その業界にいるのに、自分はまだ十分ではないと感じ、多くの専門用語を理解しなければならないこともあるでしょう。
Details
Details
5ヶ月前
IT業界の初心者が知っておくべきの用語(2025版)
SEOは聞いたことありますよね?ではGEOってご存知ですか?|生成エンジン最適化(GEO)の重要性や必要なことをまとめました!
SEOは知ってるけどGEOは初耳?AI時代に欠かせない「生成エンジン最適化(GEO)」の意味・必要性・対策ポイントを初心者向けにやさしく解説!
WASABI
WASABI
4ヶ月前
SEOは聞いたことありますよね?ではGEOってご存知ですか?|生成エンジン最適化(GEO)の重要性や必要なことをまとめました!
SafariでGoogleフォントが正しく表示されない原因と対策【font-weight・font-style完全ガイド】
SafariやiOSでGoogleフォントが正しく表示されない主な原因と対策を徹底解説。font-weight・font-styleの指定ミスによるWebフォント崩れを解決するCSSサンプル付きガイド。
aki0o0
aki0o0
6ヶ月前
SafariでGoogleフォントが正しく表示されない原因と対策【font-weight・font-style完全ガイド】
JSでウェブサイトのフッターにあるCopyrightの年数範囲を自動更新する
autoCopyright(startYear, elementId) 関数は、指定した開始年から現在年までの著作権表記(例: "2020 - 2025")を自動生成し、指定されたHTML要素に表示します。
Details
Details
6ヶ月前
JSでウェブサイトのフッターにあるCopyrightの年数範囲を自動更新する
JavaScriptでURL(パス)からファイル名を取得する
window.location.pathname でURLのパス部分を取得。 lastIndexOf('/') で最後のスラッシュ位置を検出。 substring でスラッシュの次から最後までを切り出し、ファイル名を抽出。
Details
Details
6ヶ月前
JavaScriptでURL(パス)からファイル名を取得する
scroll-behaviorで平滑スクロール、一行でいけるんだ
一般的に、アンカーリンクをスムーズにスクロールさせる時、JavaScriptやjQueryで実装することが多いです。例えば、 でも実は、CSSだけでもできるんです。そのためのプロパティがこちら: これを書くだけで、リンクをクリックした時にス […]
メモ・ノートスケ
メモ・ノートスケ
6ヶ月前
scroll-behaviorで平滑スクロール、一行でいけるんだ
フッターのJavaScriptは画像読み込みに影響する?ブラウザの読み込み順と最適化の基本
はじめに Webサイトの表示速度や操作感は、単にコンテンツの量や見た目だけでなく、ブラウザがリソースをどのように読み込むかによっても大きく左右されます。特にJavaScriptや画像の読み込み順序、そしてそれらがどのように相互作用しているか […]
解構人
解構人
5ヶ月前
フッターのJavaScriptは画像読み込みに影響する?ブラウザの読み込み順と最適化の基本
JavaScript を使って通貨形式を数値に変換する
JavaScriptの正規表現を利用し、通貨表記に含まれる無効な記号を取り除くことで、簡単に通貨文字列を数値に変換できます。これにより、数値計算や金額比較などが容易になります。
Details
Details
6ヶ月前
JavaScript を使って通貨形式を数値に変換する
CSSで等間隔配置を実現:1行に複数または複数行に配置
CSSでは、特にレスポンシブデザインにおいて、複数の要素を等間隔に配置する必要があります。列数や間隔を動的に制御することで、柔軟なレイアウトが実現可能です。この記事では、FlexboxとGridの2つの方法を使って、1行に複数のアイテムを等間隔に配置する方法を紹介します。コード内の変数(列数や間隔)を調整することで、1行に表示するアイテム数やその間隔を簡単に管理でき、レイアウト調整が容易になり、開発効率が大幅に向上します。
無敵の小さな蚊
無敵の小さな蚊
5ヶ月前
CSSで等間隔配置を実現:1行に複数または複数行に配置
ページ遷移の一般的な方法
本記事では、Webページにおけるページ遷移(リダイレクト)の一般的な実装方法について紹介しています。JavaScript、HTMLのメタタグ、PHP、ASPを用いたリダイレクト方法をそれぞれ具体的なコード例と共に解説しています。
Details
Details
6ヶ月前
ページ遷移の一般的な方法
【2025年6月最新版】TIOBEインデックスで見る人気プログラミング言語ランキングとは?
2025年6月最新版のTIOBEインデックスから、今人気のプログラミング言語を解説。Python、C、C++、Javaなどの注目度や、インデックスの活用方法も紹介します。
解構人
解構人
5ヶ月前
【2025年6月最新版】TIOBEインデックスで見る人気プログラミング言語ランキングとは?
相対パスと絶対パスの使い方
相対パスは、モジュールやディレクトリ内のローカルな参照に適しており、柔軟性があります。一方、絶対パスはウェブサイト全体で共通のリソース(CSS、画像、CDNなど)を参照する際に便利です。両者を理解して使い分けることで、パスのエラーや読み込み不具合を防げます。
Details
Details
5ヶ月前
相対パスと絶対パスの使い方