Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

바닐라 JavaScript로 모달 창 외부 클릭 시 자동으로 닫는 방법

바닐라 JavaScript만으로 사용자가 모달 창(또는 다른 UI 요소)의 바깥을 클릭했을 때 이를 닫는 방법을 알아보겠습니다.

모달 팝업은 대체로 짜증나는 존재입니다. 특히 화면 전체를 덮어버리면 더욱 그렇죠. 웹사이트에 들어온 지 몇 초 만에 팝업이 뜬다면 더더욱 불쾌합니다. 이건 어리석은 방식이며, 분명히 나쁜 UX 디자인입니다.

일부 사이트는 한 단계 더 나아가 닫기(X) 버튼을 너무 작게 만들거나 엉뚱한 위치에 배치해 버립니다. 마치 퍼즐을 풀듯 버튼을 찾아 헤매다 보면, 처음 그 사이트를 방문한 이유마저 잊어버릴 지경이 되죠.

이제 이 문제를 해결해 보겠습니다.

HTML: 간단한 모달 창

HTML 문서에 다음 코드를 추가하세요:

<main>
  <div class="modal">
    <button class="button-close-modal">X</button>

    <h2>Subscribe to my Newsletter</h2>

    <p>Get access to exclusive content that only share with my email list</p>

    <label for="email">Enter your email:</label>
    <input type="email" id="email" name="email" />
  </div>
</main>

CSS: 모달과 버튼 스타일링

.modal {
  padding: 2rem;
  border: 1px solid #eee;
  width: max-content;
  position: fixed;
  right: 0;
  bottom: 0;
  max-width: 100%;
}

.button-close-modal {
  display: block;
  font-size: 2rem;
  font-weight: bold;
  margin-left: auto;
}

JavaScript: 문서 전체의 클릭 감지하기

다음 JavaScript 코드는 사용자가 모달 요소의 바깥을 클릭하거나 X 버튼을 클릭했을 때 모달 창을 닫습니다:

document.addEventListener(
  "click",
  function(event) {
    // 사용자가 X 버튼을 클릭하거나 모달 창 바깥을 클릭하면
    // closeModal()을 호출해 모달을 닫습니다.
    if (
      event.target.matches(".button-close-modal") ||
      !event.target.closest(".modal")
    ) {
      closeModal()
    }
  },
  false
)

function closeModal() {
  document.querySelector(".modal").style.display = "none"
}

전체 코드는 위 예제를 그대로 복사해 프로젝트에 붙여 넣으면 바로 사용할 수 있습니다.

코드 동작 원리

  • 클릭 이벤트 리스너 등록: 먼저 document 객체에 클릭 이벤트 리스너를 등록합니다. 이렇게 하면 HTML 문서 어디에서 발생한 클릭이든 모두 감지되며, 중괄호 { .. } 안에 작성한 로직이 매 클릭마다 실행됩니다.
  • 두 가지 닫기 조건: 모달 창을 닫는 경로를 두 가지로 설정합니다. 하나는 닫기 버튼 클릭, 다른 하나는 모달 창 바깥 영역 클릭입니다.
  • if 문의 조건 판별: if 문 안에서는 "클릭된 대상이 닫기 버튼(matches(".button-close-modal"))과 일치하거나(||), 모달 창 밖에서 발생한 클릭(!event.target.closest(".modal"))이라면 closeModal() 함수를 호출하라"고 정의합니다.
  • 모달 숨기기: closeModal() 함수가 호출되면 .modal 클래스 선택자로 요소를 찾은 뒤 display = 'none'을 적용해 화면에서 숨깁니다.

closest() 메서드는 인자로 전달한 선택자와 일치하는 가장 가까운 상위(부모) 요소를 탐색합니다. 이 예제에서는 클래스 선택자 .modal을 전달했습니다.

matches() 메서드는 event.target, 즉 실제로 클릭된 요소가 특정 선택자와 일치하는지 검사합니다. 여기서는 닫기 버튼의 클래스 선택자인 .button-close-modal과 비교합니다.

추가 팁: 모달이 열리자마자 닫히는 현상 방지

버튼 클릭으로 모달을 여는 경우, 그 클릭 이벤트가 문서까지 전파(bubbling)되어 모달이 열리자마자 곧바로 닫히는 문제가 생길 수 있습니다. 이럴 때는 모달을 여는 핸들러에서 event.stopPropagation()을 호출해 이벤트 전파를 차단하면 됩니다.