모달 창이란 사용자 인터페이스 디자인 개념에서 자식 윈도에서 부모 윈도로 돌아가기 전에 사용자의 상호동작을 요구하는 창을 말합니다. 아래 그림에서 가운데 하얀색 부분이 그 예라고 할 수 있습니다.

이 모달창은 팝업과 비슷하게 정보를 전달하나 팝업과 다르게 별도의 창이나 탭을 생성하지 않고 페이지 내에서 레이어를 이용해 정보를 보여준다는 점이 차이점이라고 할 수 있습니다.

여기서 만들 모달 창은 디자인이나 모듈화 같은 고급 기법보다는 기본적인 이벤트 중심으로만 설명하겠습니다. 모달 창은 기본적으로 다음 이벤트를 가집니다.

  • 특정 버튼을 누르면 모달창이 켜집니다.
  • 모달창의 클로즈(x) 버튼을 누르면 모달창이 꺼집니다.
  • 모달창 바깥 영역 (위 그림에서 밝기가 어두운 부분) 을 클릭하면 모달창이 꺼집니다.
  • 모달창이 켜진 상태에서 ESC 버튼을 누르면 모달창이 꺼집니다.

 

HTML + CSS로 모달창 만들기

일단 아무 기능이 없는 모달창을 만들어 보겠습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Modal</title>
    <style>
        #modal.modal-overlay {
            width: 100%;
            height: 100%;
            position: absolute;
            left: 0;
            top: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;

            background: rgba(255, 255, 255, 0.25);
            box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
            backdrop-filter: blur(1.5px);
            -webkit-backdrop-filter: blur(1.5px);
            border-radius: 10px;
            border: 1px solid rgba(255, 255, 255, 0.18);
        }

        #modal .modal-window {

            background: rgba( 69, 139, 197, 0.70 );
            box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.37 );
            backdrop-filter: blur( 13.5px );
            -webkit-backdrop-filter: blur( 13.5px );
            border-radius: 10px;
            border: 1px solid rgba( 255, 255, 255, 0.18 );

            width: 400px;
            height: 500px;
            position: relative;
            top: -100px;
            padding: 10px;
        }

        #modal .title {
            padding-left: 10px;
            display: inline;
            text-shadow: 1px 1px 2px gray;
            color: white;
            
        }

        #modal .title h2 {
            display: inline;
        }

        #modal .close-area {
            display: inline;
            float: right;
            padding-right: 10px;
            cursor: pointer;
            text-shadow: 1px 1px 2px gray;
            color: white;
        }
        
        #modal .content {
            margin-top: 20px;
            padding: 0px 10px;
            text-shadow: 1px 1px 2px gray;
            color: white;
        }
    </style>
</head>

<body>
    <div id="container">
        <h2>Lorem Ipsum</h2>
        <button id="btn-modal">모달 창 열기 버튼</button>
        <div id="lorem-ipsum"></div>
    </div>

    <div id="modal" class="modal-overlay">
        <div class="modal-window">
            <div class="title">
                <h2>모달</h2>
            </div>
            <div class="close-area">X</div>
            <div class="content">
                <p>가나다라마바사 아자차카타파하</p>
                <p>가나다라마바사 아자차카타파하</p>
                <p>가나다라마바사 아자차카타파하</p>
                <p>가나다라마바사 아자차카타파하</p>
                
            </div>
        </div>
    </div>

    <script>
        const loremIpsum = document.getElementById("lorem-ipsum")

        fetch("https://baconipsum.com/api/?type=all-meat&paras=200&format=html")
            .then(response => response.text())
            .then(result => loremIpsum.innerHTML = result)
    </script>
</body></html>

이 모달창은 기본적인 틀만 유지한다면 자유롭게 디자인해도 상관없습니다. 다만, 맨 위의 그림에서 배경이 어두워진것을 볼 수 있는데 이런 식으로 모달창과만 인터랙션하도록 유도할 필요가 있습니다. 이 부분을 오버레이라 하며, 브라우저 창 전체를 덮는 형태로 설정한 다음 모달창을 그 위에 올려놓으면 됩니다.

그리고 오버레이 레이어 display: flex 부분을 통해 모달 창을 한가운데로 위치시킬 수 있습니다.

이 모달에 이벤트를 부여하겠습니다.

 

특정 버튼을 누르면 모달창이 켜지게 하기

모달의 초기 상태를 display: none;으로 했다가 특정 버튼을 클릭하면 display: flex; 으로 변하게 하면 됩니다.

#modal.modal-overlay {
    ... 
    display: none;
    ...  
}
const modal = document.getElementById("modal")
const btnModal = document.getElementById("btn-modal")
btnModal.addEventListener("click", e => {
    modal.style.display = "flex"
})

 

모달창의 클로즈(x) 버튼을 누르면 모달창이 꺼지게 하기

X(클로즈) 버튼에 위 예제와 반대되는 이벤트를 부여합니다.

const closeBtn = modal.querySelector(".close-area")
closeBtn.addEventListener("click", e => {
    modal.style.display = "none"
})

 

모달창 바깥 영역을 클릭하면 모달창이 꺼지게 하기

모달 영역 외의 오버레이를 클릭하면 꺼지는 이벤트를 만들면 됩니다.

modal.addEventListener("click", e => {
    const evTarget = e.target
    if(evTarget.classList.contains("modal-overlay")) {
        modal.style.display = "none"
    }
})

모달 창 외의 영역을 클릭하면 이벤트 타깃 요소에 modal-overlay 클래스가 있으므로 종료하고, 모달 창을 클릭하면 이벤트 타깃 요소에 modal-overlay가 없기 때문에 종료하지 않습니다.

그리고 모달 오버레이에 이벤트를 부여함으로써 모달 창 및 오버레이 외 다른 요소에 이벤트를 부여할 필요도 없습니다.

 

모달창이 켜진 상태에서 ESC 버튼을 누르면 모달창이 꺼지게 하기
window.addEventListener("keyup", e => {
    if(modal.style.display === "flex" && e.key === "Escape") {
        modal.style.display = "none"
    }
})

모달이 켜져 있는 상태에서, 그 키가 ESC 키라면 창을 닫습니다.

 

전체 자바스크립트 코드는 다음과 같습니다.

const loremIpsum = document.getElementById("lorem-ipsum")

fetch("https://baconipsum.com/api/?type=all-meat&paras=200&format=html")
    .then(response => response.text())
    .then(result => loremIpsum.innerHTML = result)

const modal = document.getElementById("modal")

function modalOn() {
    modal.style.display = "flex"
}

function isModalOn() {
    return modal.style.display === "flex"
}

function modalOff() {
    modal.style.display = "none"
}


const btnModal = document.getElementById("btn-modal")
btnModal.addEventListener("click", e => {
    modalOn()
})

const closeBtn = modal.querySelector(".close-area")
closeBtn.addEventListener("click", e => {
    modalOff()
})

modal.addEventListener("click", e => {
    const evTarget = e.target
    if(evTarget.classList.contains("modal-overlay")) {
        modalOff()
    }
})

window.addEventListener("keyup", e => {
    if(isModalOn() && e.key === "Escape") {
        modalOff()
    }
})

 

문의 | 코멘트 또는 yoonbumtae@gmail.com


카테고리: WEB: Frontend


8개의 댓글

odong · 2022년 1월 7일 4:51 오후

좋은 정리입니다. 감사합니다 🙂

dablesniper · 2022년 1월 20일 2:49 오후

버튼 태그가 빠지긴 했는데 정말 많은 도움 받아갑니다. 감사합니다.

tjdtlf · 2022년 9월 23일 3:28 오후

Lorem Ipsum 제목 아래에 버튼 태그 추가해야 클릭이 되네요 감사합니다~

모달창 열기

    yoonbumtae (BGSMM) · 2022년 9월 23일 4:32 오후

    예제 코드에서 버튼 태그가 빠져있었네요 알려주셔서 감사합니다.

코딩함냠냠 · 2022년 9월 27일 11:21 오전

정리글 게재해주셔서 감사합니다 링크퍼가겠습니다

감자감자 · 2023년 2월 2일 8:47 오후

고맙습니다~ 적용해보고 잘 쓸게욥

말하는감자 · 2023년 3월 23일 2:33 오전

감사합니다 제가 원하는 모양 만들 수 있을 거 같아요….
한참으 ㄹ헤맸는데 여기가 제일 이해 잘 되요
잘쓰겠습니다!!!

holim · 2023년 3월 24일 1:06 오후

모달창 바깥 영역 클릭할때 모달 창 닫기 구현하는데 어려움이 있었는데,
알려주신 e.target.classList.contains로 설정하여서 해당 target 요소일때만 이벤트 발생한다는 것을 알게 되어 많은 도움 받아 갑니다 감사합니다.

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다.

계산결과를 입력해주세요 (스팸댓글 방지용) 99 − = 94