範囲外をクリックしてポップアップを閉じる方法【jQuery】

この記事の前提条件

対象: jQuery(既存のjQuery環境での実装を想定)
難易度: ★★☆
所要時間: 約5分

検索窓の候補一覧や、ハンバーガーメニューを開いた時、ポップアップの外側をクリックしたら自動で閉じてほしいのは、ユーザーからすると当たり前の挙動です。実装の考え方自体はシンプルですが、書き方を間違えると開いた瞬間に閉じてしまう、というつまずきが起きやすい機能でもあります。

基本の考え方: クリックされた場所が対象の外かどうかを判定する

$(document).on('click', function(e) {
  if (!$(e.target).closest('.popup').length) {
    $('.popup').removeClass('is-active');
  }
});

closest('.popup')は、「クリックされた要素自身か、その親をたどっていった先に.popupが見つかるか」を調べています。見つからない(.lengthが0)場合は「ポップアップの外側がクリックされた」と判断できるので、閉じる処理を実行します。

⚠️ 開くボタンのクリックまで拾って一瞬で閉じてしまう問題

この機能で一番よくあるつまずきが、「ポップアップを開くボタン自体のクリック」までdocumentのクリックイベントが拾ってしまい、開いた瞬間に外側クリック判定されて即座に閉じてしまう、という現象です。原因は、ボタンをクリックした時に「ポップアップを開くイベント」と「documentのクリックイベント(閉じる判定)」が同じタイミングで両方発火してしまうことです。

解決法: 開くボタンも判定対象に含める

「ポップアップの中」だけでなく「開くボタン自体」もクリック対象として除外することで解決します。

$(document).on('click', function(e) {
  if (
    !$(e.target).closest('.popup').length &&
    !$(e.target).closest('.popup-open-btn').length
  ) {
    $('.popup').removeClass('is-active');
  }
});

「ポップアップの中でもなく、開くボタンでもない場所がクリックされた時だけ閉じる」という条件にすることで、開いた瞬間に閉じてしまう不具合を防げます。

まとめ

  • closest()で「クリック位置がポップアップの中かどうか」を判定する
  • 開くボタン自体も判定に含めないと、開いた瞬間に閉じてしまう不具合が起きる
  • 「ポップアップの中でも開くボタンでもない場所」という条件で判定するのが安全