그룹 요소 전환

목록에서 항목이 추가, 삭제 또는 재정렬될 때 전환을 사용하면 사용자가 컨텍스트를 유지하는 데 도움이 됩니다. 뷰 전환은 요소에 고유한 view-transition-name를 부여하여 요소의 두 상태 간에 전환하는 방법을 제공합니다. 페이지의 여러 요소가 동일한 전환 동작을 공유하는 경우 view-transition-class를 사용하면 모든 고유한 view-transition-name에 대해 반복하는 대신 CSS에서 해당 로직을 한 번 정의할 수 있습니다. 이렇게 하면 스타일시트를 유지 관리할 수 있으면서도 요소 그룹 전체에서 일관된 애니메이션을 보장할 수 있습니다.

구현 단계

  1. 고유한 이름 및 공유 수업 할당하기

    전환 중에 개별적으로 추적해야 하는 각 요소에는 고유한 view-transition-name가 있어야 합니다.

    <!-- Mandatory: Each element must have a unique view-transition-name -->
    <li style="view-transition-name: item-1" class="item">Item 1</li>
    <li style="view-transition-name: item-2" class="item">Item 2</li>
    

    공유 스타일을 적용하려면 view-transition-class도 할당합니다.

    .item {
      view-transition-class: list-item;
    }
    
  2. 공유 전환 로직 정의

    클래스 선택기와 함께 ::view-transition-group() 가상 요소를 사용하여 해당 그룹의 모든 구성원에게 스타일을 적용합니다.

    /* Targets any view transition group that has the 'list-item' class */
    ::view-transition-group(.list-item) {
      animation-duration: 0.5s;
      animation-timing-function: ease-in-out;
    }
    
    /* Handle accessibility by respecting motion preferences */
    @media (prefers-reduced-motion: reduce) {
      /* Disable all group transitions, including the default `root` group. */
      ::view-transition-group(*),
      ::view-transition-old(*),
      ::view-transition-new(*) {
        animation: none !important;
      }
    }
    
  3. 선택사항: 들어가기 및 나가기 애니메이션 정의

    :only-child 선택기를 사용하여 추가되거나 삭제되는 요소에 특정 전환을 추가합니다. ::view-transition-new() 및 ::view-transition-old() 가상 요소는 ::view-transition-image-pair() 가상 요소의 하위 요소이므로 유일한 하위 요소인 경우 추가되거나 삭제된 요소인지 확인할 수 있습니다.

    /* A `::view-transition-new()` element is the only child if it wasn't present before the view transition, so it is an added element. */
    ::view-transition-new(.list-item):only-child {
      animation-name: slide-in;
      /* Specify an animation duration if you want something different than the UA default of 0.5s */
      animation-duration: 1s;
    }
    /* A `::view-transition-old()` element is the only child if it isn't present after the view transition, so it is a removed element. */
    ::view-transition-old(.list-item):only-child {
      animation-name: slide-out;
      /* Specify an animation duration if you want something different than the UA default of 0.5s */
      animation-duration: 1s;
    }
    
    @keyframes slide-in {
      from {
        translate: -100vw 0;
      }
    }
    @keyframes slide-out {
      to {
        translate: -100vw 0;
      }
    }
    
  4. 전환 트리거

    document.startViewTransition()로 DOM 업데이트를 래핑합니다. 브라우저는 이전 상태를 캡처하고 업데이트를 실행한 후 새 상태로 애니메이션을 적용합니다.

    function updateList(newData) {
      document.startViewTransition(() => {
        // All DOM changes inside this callback will be transitioned
        render(newData);
      });
    }
    
  5. 전환되지 않은 요소의 상호작용 유지

뷰 전환은 DOM 요소의 스냅샷을 오버레이한 다음 스냅샷을 전환하는 방식으로 작동합니다. 즉, 전환 중에는 요소가 상호작용하지 않습니다. 전환되지 않는 상호작용 요소가 있는 경우 뷰 전환에서 터치 이벤트를 사용 중지하여 상호작용 요소로 만들 수 있습니다.

::view-transition {
  /* Non-transitioned elements below the view transitions remain interactive */
  pointer-events: none;
}

또한 기본적으로 :root 요소에는 root라는 뷰 전환이 있어 기본 전체 페이지 전환을 사용 설정합니다. 루트 요소에 변경사항이 없으면 상호작용이 불가능한 두 개의 동일한 스냅샷 간의 전환이 됩니다. 전체 화면이 아닌 특정 요소만 전환하므로 root 전환을 사용 중지할 수 있습니다.

:root {
  /* Disable the root transition because we are only transitioning specific elements. */
  view-transition-name: none;
}

대체 전략

뷰 전환은 점진적 개선입니다. 브라우저가 document.startViewTransition를 지원하지 않는 경우에도 DOM 업데이트는 즉시 실행되어야 하며, 애니메이션이 없는 기능적 환경을 제공해야 합니다.

if (document.startViewTransition) {
  document.startViewTransition(() => updateDOM());
} else {
  // Fallback: Perform the update without animation
  updateDOM();
}

CSS의 경우 view-transition-class 또는 ::view-transition-group() 클래스 선택자를 인식하지 못하는 브라우저는 해당 규칙을 무시하고 애니메이션을 적용하지 않습니다.