두 단계로 표시되지 않는 요소에 애니메이션을 적용하는 방법

4363 단어 css
이제 숨겨진 요소에 애니메이션을 적용하는 것이 매우 간단합니다. 상태 열기/닫기를 전환하려면 2개의 CSS 선언과 약간의 JavaScript만 있으면 됩니다.

해결책





이 문서에서:


  • CSS:not 의사 선택기
  • 진실의 단일 소스
  • animationend 이벤트
  • 접근성

  • 우리가 해결하려고 하는 문제


    hidden 속성을 가진 숨겨진 요소가 있습니다. 더 나은 UX를 제공하기 위해 이 열기 및 닫기 상태를 애니메이션화하려고 합니다. 그러나 CSS에서 display:none는 인터럽터와 같습니다. "켜짐"또는 "꺼짐"일 수 있지만 CSS 전환으로 두 상태 간에 애니메이션을 적용하는 것은 불가능합니다.

    1단계: 여는 동안 애니메이션



    HTML

    <a href="#modal" class="modal-button">Open Modal</a>
    <div class="modal" id="modal" hidden>Modal content</div>
    


    아시다시피 버튼 대신 링크를 선택하겠습니다. 왜요 ? 내 모달은 target CSS 의사 클래스 덕분에 JavaScript 없이 계속 액세스할 수 있기 때문입니다. 이후에 이 점에 중점을 둘 것입니다.

    모달을 표시하는 JS




    modalButton.addEventListener("click", function (e) {
      e.preventDefault();
      modal.hidden = false;
    });
    


    CSS




    .modal:not([hidden]) {
      animation-name: popIn;
    }
    


    그게 다야. ¯_(ツ)_/¯.
    Tailwind와 같이 .hidden 클래스에 의존하는 것을 선호하는 경우 :not([hidden]):not(.hidden) 로 전환할 수 있습니다. 둘 다 원하는 경우 not 의사 클래스는 쉼표로 구분된 여러 인수를 허용합니다. : not([hidden], .hidden) . 어쨌든 이제 Modal이 반짝이는 애니메이션과 함께 나타납니다.



    2단계 : 닫는 동안 애니메이션



    닫는 상태는 조금 더 까다롭습니다. hidden 속성을 "true"로 설정하면 매끄럽게 숨길 수 없습니다. is-closing와 같은 임시 클래스를 추가하여 닫는 애니메이션을 재생한 다음 요소를 숨길 필요가 있습니다.

    JS




    modal.addEventListener("click", function (e) {
      // Omitted…
      if (hasClickedOutside || hasClickedCloseButton) {
        modal.classList.add("is-closing");
        // Omitted…
    


    CSS




    .modal.is-closing {
      animation-name: popOut;
    }
    



    이제 모달이 부드럽게 닫히지만 숨겨진 상태로 돌아가지는 않습니다. .is-closing 클래스를 제거하고 hidden="true" 로 돌아가려면 애니메이션이 끝날 때까지 기다려야 합니다. setTimeout ? 할 수 있지만 더 나은 옵션이 있습니다.

    애니메이션 종료 이벤트


    timeout 를 사용하면 변경될 수 있는 애니메이션 지속 시간과 최소한 같은 값을 선언해야 합니다.
    가능하다면 단일 정보 소스, 즉 CSS에 선언된 애니메이션 기간이 있어야 합니다.animationend는 애니메이션이 끝날 때까지 기다린 다음 리스너 내에서 함수를 실행합니다.

    modal.addEventListener("click", function (e) {
      const hasClickedOutside = !e.target.closest(".modal-main");
      const hasClickedCloseButton = e.target.closest(".modal-close");
    
      if (hasClickedOutside || hasClickedCloseButton) {
        modal.classList.add("is-closing");
    
        modal.addEventListener(
          "animationend",
          function () {
            modal.hidden = true;
            modal.classList.remove("is-closing");
          },
          { once: true }
        );
      }
    });
    


    이벤트가 완료되면 더 이상 필요하지 않으므로 once: true 옵션을 사용하여 제거해야 합니다.
    그리고 짜잔, DOM에 숨겨진 모든 요소를 ​​애니메이션화할 수 있는 지식이 있습니다.

    보너스 : 약간의 접근성 향상


    버튼 대 링크



    위에서 말했듯이 다음과 같은 이유로 <a> 대신 <button>를 선택합니다.

    .modal:target {
      display: grid !important;
      animation-name: popIn;
      .modal-close {
        display: none;
      }
    }
    


    JS가 없으면 모달은 여전히 ​​해시를 통해 열 수 있으며 :target 유사 클래스를 사용하여 열린 상태의 스타일을 지정할 수 있습니다.
    닫으려면 사용자가 기록으로 돌아가야 합니다. 이것이 내가 .modal-close를 숨기는 이유입니다. 아무것도 할 수 없다면 그것을 보여주는 것은 적절하지 않습니다.

    사용자가 애니메이션을 원하지 않으면 애니메이션을 재생하지 마십시오.



    개인적인 취향, 의학적 이유 또는 장치의 성능 문제를 해결하기 위해 사용자는 애니메이션을 원하지 않을 수 있으므로 사용자의 기본 설정을 존중해야 합니다. 아직 완료되지 않은 경우 CSS 재설정의 일부로 다음 규칙을 포함하는 것이 좋습니다.

    @media (prefers-reduced-motion: reduce) {
      *,
      *::before,
      *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
      }
    }
    


    읽어 주셔서 감사합니다. 👋

    좋은 웹페이지 즐겨찾기