바닐라 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()을 호출해 이벤트 전파를 차단하면 됩니다.