요소 숨김 방식 차이점


렌더 트리 리플로우 리페인트 이벤트 핸들러 DOM 트리
display: none 제외 발생 발생 비활성 유지
visibility: hidden 유지 발생 안함 발생 비활성 유지
opacity: 0 유지 발생 안함 발생 활성 유지
  1. display: none
  2. visibility: hidden
  3. opacity: 0

팝업 애니메이션 구현


HTML 기본 구조

<button class="open-popup-btn">팝업창 열기</button>
<div class="popup">
  <h2> 팝업 Window </h2>
  <button>버튼1</button>
  <button>버튼2</button>
	<button>버튼3</button>
</div>

방법 1 | display: none 사용

  1. .popup 클래스는 기본적으로 보이지 않도록 설정. display: none; 속성은 박스가 생성되지 않기 때문에 공간도 차지하지 않는다.

    .popup {
      display: none;
    }
    
  2. 버튼을 클릭하면 .visible 클래스 추가하도록 자바스크립트 코드 작성

    const openBtn = document.querySelector(".open-popup-btn");
    const popup = document.querySelector(".popup");
    
    openBtn.addEventListener("click", () => {
      if (!popup.classList.contains("visible")) {
        popup.classList.add("visible");
      } else {
    		popup.classList.remove('visible')
      }
    });
    
  3. .visible 클래스 스타일 설정

    transform: translatey(...)를 설정하면 입력한 값의 y축부터 위로 올라오는 효과를 낸다. 팝업창이 점점 커지는 효과를 내려면 0%(from)일 때 height: 0% 속성을 주면 된다. opacity는 투명도 설정. 0은 완전 투명, 1은 불투명(투명도 없음)이므로 완전 투명(from)했다가 점점 불투명(to)으로 변한다.

    @keyframes popup {
      0% {
        opacity: 0;
        transform: translatey(50%);
      }
    
      100% {
        opacity: 1;
        transform: none;
      }
    }
    
    .popup.visible {
      background: #f8f1e7;
      position: absolute;
      bottom: 0;
      width: 350px;
      height: 350px;
      border: 1px solid black;
      border-radius: 20px 20px 0 0;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      animation: popup 0.5s ease-in-out;
    }
    
  4. 팝업창이 사라질 때도 효과를 주고 싶다면 JS를 아래처럼 수정. 팝업창이 올라온 상태(visible 클래스 추가 상태)에서 버튼을 누르면 .disappear 클래스가 추가되고 400ms 후에 .visible 클래스가 사라진다. display: none 상태일 땐 transition 속성이 적용되지 않기 때문에 .disappear 클래스를 따로 추가해서 애니메이션 효과를 먼저 보여준 후 일정 시간 이후 display: none 속성이 적용되도록 하는 방법.

    const openBtn = document.querySelector(".open-popup-btn");
    const popup = document.querySelector(".popup");
    
    openBtn.addEventListener("click", () => {
      if (!popup.classList.contains("visible")) {
        popup.classList.remove('disappear');
        popup.classList.add("visible");
      } else {
        popup.classList.add("disappear");
        setTimeout(() => popup.classList.remove("visible"), 400);
      }
    });
    

    .popup.disappear클래스에 대한 스타일도 설정해야 한다. animation 속성으로 설정할 수도 있지만, 아래처럼 width 값을 팝업창 크기와 동일하게, height는 0, transition 값을 주면 아래로 스르륵 사라지는 효과를 낸다. width 값도 0으로 주면 요술램프처럼 한 곳으로 쏠려서 사라진다.

    transition의 all 속성은 width, height 크기 변화에 모두 transition 효과를 준다. width 혹은 height만 입력해서 해당 크기 변화에 대해서만 효과를 줄 수도 있다. transition: all 0.5s ease-in-out속성은 hover 효과를 점진적으로 표시하고 싶을 때도 유용하다.

    .popup.disappear {
      width: 350px;
      height: 0;
      transition: all 0.5s ease-in-out;
    }
    

방법 2 | visibility: hidden 사용

<aside> 💡 부모 요소 혹은 뷰포트 크기에 따라 높이가 동적이라면 height 대신 max-height를 이용하면 된다

</aside>

visibility: hidden 속성을 사용해도 화면에선 사라지지만, display: none과 가장 큰 차이점은 공간을 차지한다는 것. 따라서 팝업창이 올라오지 않을때의 기본 height는 0px로 설정해둔다. visibility 속성을 사용하면 animation을 쓰지 않고 transition만 사용해도 비슷한 효과를 낼 수 있다.

.popup {
	visibility: hidden;
	background: #f8f1e7;
  position: absolute;
  bottom: 0;
  width: 350px;
  height: 0px; /* max-height: 0px */
  border: 1px solid black;
  border-radius: 20px 20px 0 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
	transition: all 0.5s ease-in-out;
}

.popup.visible {
	visibility: visible;
	height: 350px; /* max-height: 350px */
}

자바스크립트 코드는 visible 클래스가 추가/삭제되는 toggle만 추가하면 된다.

const openBtn = document.querySelector(".open-popup-btn");
const popup = document.querySelector(".popup");

openBtn.addEventListener("click", () => {
  popup.classList.toggle('visible')
});