원활한 시작 및 종료 애니메이션을 위한 4가지 새로운 CSS 기능

조이 아르하르
조이 아르하르

모션은 모든 디지털 경험의 핵심으로, 사용자를 한 상호작용에서 다음 상호작용으로 안내합니다. 하지만 웹 플랫폼에서는 자연스러운 애니메이션에 약간의 차이가 있습니다. 이러한 기능으로는 진입 및 이탈 애니메이션에 쉽게 애니메이션을 적용하고 대화상자 및 팝오버와 같이 닫을 수 있는 요소를 위해 상단 레이어로 또는 상단 레이어에서 부드럽게 애니메이션 처리할 수 있는 기능이 포함됩니다.

이러한 공백을 메우기 위해 Chrome 116 및 117에는 개별 속성에 매끄러운 애니메이션과 전환을 지원하는 4가지 새로운 웹 플랫폼 기능이 포함되어 있습니다.

새로운 4가지 기능은 다음과 같습니다.

  • 키프레임 타임라인에서 displaycontent-visibility에 애니메이션을 적용하는 기능 (Chrome 116부터)
  • display와 같은 개별 속성을 전환할 수 있도록 하는 allow-discrete 키워드가 있는 transition-behavior 속성 (Chrome 117부터)
  • @starting-style 규칙은 display: none에서 최상위 레이어로 항목 효과를 애니메이션으로 보여줍니다 (Chrome 117부터).
  • 애니메이션 도중 상단 레이어 동작을 제어하는 overlay 속성 (Chrome 117부터) ## 키프레임에 애니메이션 표시

Chrome 116부터 키프레임 규칙에서 displaycontent-visibility를 사용할 수 있습니다. 그러면 키프레임이 발생하는 시점에 서로 변경됩니다. 이를 지원하는 데 새로운 값이 추가로 필요하지는 않습니다.

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

위의 예에서는 0.5초 동안 불투명도를 0으로 애니메이션 처리한 다음 display display를 none으로 설정합니다. 또한 forwards 키워드는 애니메이션이 최종 상태로 유지되도록 하여 적용되는 요소가 display: noneopacity: 0로 유지되도록 합니다.

다음은 전환으로 할 수 있는 작업을 모방한 간단한 예입니다 (전환 섹션의 데모 참고). 그러나 전환은 다음 예와 같이 더 복잡한 애니메이션을 만들 수 없습니다.

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

spin-and-delete 애니메이션은 종료 애니메이션입니다. 먼저 카드가 y축에서 회전하고 색조 순환을 통해 실행된 다음 80%에서 타임라인을 통해 불투명도를 1에서 0으로 전환합니다. 마지막으로 카드가 display: block에서 display: none로 전환됩니다.

이러한 이탈 애니메이션의 경우 요소에 직접 적용하는 대신 애니메이션 트리거를 설정할 수 있습니다. 예를 들어 다음과 같이 애니메이션 적용을 위한 클래스를 트리거하는 버튼에 이벤트 리스너를 연결합니다.

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

이제 위의 예의 최종 상태는 display:none입니다. 더 나아가 애니메이션이 먼저 완료될 수 있도록 시간 제한으로 DOM 노드를 제거하려는 경우가 많이 있습니다.

불연속 애니메이션 전환

키프레임으로 불연속 속성에 애니메이션을 적용할 때와 달리 불연속 속성을 전환하려면 allow-discrete 전환 동작 모드를 사용해야 합니다.

transition-behavior 속성

allow-discrete 모드는 불연속 전환을 가능하게 하는 모드이며 transition-behavior 속성의 값입니다. transition-behaviornormalallow-discrete, 이렇게 두 가지 값을 허용합니다.

.card {
  transition: opacity 0.25s, display 0.25s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
참고: 이 전환 데모는 첫 번째 애니메이션 데모와 다른 기법을 보여주지만 시각적으로 유사합니다.

transition 약식에서도 이 값을 설정하므로 속성을 생략하고 대신 각 전환의 transition 약식 끝에 있는 allow-discrete 키워드를 대신 사용할 수 있습니다.

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

여러 불연속 속성에 애니메이션을 적용하는 경우 애니메이션을 적용할 각 속성 뒤에 allow-discrete를 포함해야 합니다. 예를 들면 다음과 같습니다.

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

항목 애니메이션의 @starting-style 규칙

지금까지 이 도움말에서는 종료 애니메이션을 다루었습니다. 항목 애니메이션을 만들려면 @starting-style 규칙을 사용해야 합니다.

@starting-style를 사용하여 요소가 페이지에서 열리기 전에 브라우저가 조회할 수 있는 스타일을 적용합니다. 이것이 '개방 전' 상태입니다 (애니메이션을 시작할 때).

/*  0. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  1. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

이제 이러한 TODO 목록 항목에 진입 및 종료 상태가 모두 있습니다.

상단 레이어로 또는 최상위 레이어에서 요소에 애니메이션 적용

상단 레이어에서 요소에 애니메이션을 적용하려면 '열림' 상태에서 @starting-style를 지정하여 애니메이션을 적용할 위치를 브라우저에 알립니다. 대화상자의 경우 열린 상태는 [open] 속성으로 정의됩니다. 팝오버의 경우 :popover-open 의사 클래스를 사용합니다.

대화상자의 간단한 예는 다음과 같습니다.

/*   0. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   1. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

다음 예에서는 진입 효과와 종료 효과가 다릅니다. 표시 영역의 하단에서 위쪽으로 애니메이션을 적용하여 진입하고 표시 영역의 상단으로 효과를 종료합니다. 또한 더 시각적인 캡슐화를 위해 중첩된 CSS로 작성됩니다.

팝오버를 애니메이션화할 때는 이전에 사용한 open 속성 대신 :popover-open 의사 클래스를 사용합니다.

.settings-popover {
  &:popover-open {
    /*  0. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
    
    /*  1. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

숙박 시설 overlay

마지막으로 상단 레이어에서 popover 또는 dialog를 페이드 아웃하려면 전환 목록에 overlay 속성을 추가합니다. popoverdialog는 상위 클립 및 변환을 이스케이프 처리하고, 콘텐츠를 상단 레이어에 배치합니다. overlay를 전환하지 않으면 요소가 즉시 잘리고, 변형되고, 덮인 상태로 되돌아가고 전환이 발생하지 않습니다.

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

대신 전환이나 애니메이션에 overlay를 포함하여 나머지 지형지물과 함께 overlay에 애니메이션을 적용하고 애니메이션화할 때 최상위 레이어에 계속 표시되도록 하세요. 이렇게 하면 훨씬 더 매끄럽게 표시됩니다.

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

또한 상단 레이어에서 여러 요소가 열려 있는 경우 오버레이를 사용하면 상단 레이어 안팎으로의 부드러운 전환을 제어할 수 있습니다. 이 간단한 예에서 차이를 확인할 수 있습니다. 전환할 때 두 번째 팝오버에 overlay를 적용하지 않은 경우 전환을 시작하기 전에 먼저 상단 레이어에서 다른 팝오버 뒤로 이동합니다. 이 과정은 순조롭게 진행되지는 않습니다.

뷰 전환 참고 사항

DOM에서 요소를 추가 및 삭제하는 등 DOM을 변경하는 경우, 매끄러운 애니메이션을 위한 또 다른 좋은 솔루션은 뷰 전환입니다. 다음은 뷰 전환을 사용하여 빌드된 위의 두 가지 예입니다.

이 첫 번째 데모에서는 @starting-style 및 기타 CSS 변환을 설정하는 대신 뷰 전환이 전환을 처리합니다. 뷰 전환은 다음과 같이 설정됩니다.

먼저 CSS에서 각 카드에 개별 view-transition-name를 지정합니다.

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

그런 다음 자바스크립트에서 뷰 전환에서 DOM 변형 (이 경우 카드 삭제)을 래핑합니다.

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

이제 브라우저가 각 카드의 페이드 아웃과 변이를 새로운 위치로 처리할 수 있습니다.

이 작업의 또 다른 예는 목록 항목 추가/삭제 데모를 사용하는 것입니다. 이 경우 생성된 각 카드에 고유한 view-transition-name를 추가해야 합니다.

결론

이러한 새로운 플랫폼 기능을 통해 웹 플랫폼에서의 원활한 시작 및 종료 애니메이션에 한 걸음 더 가까워졌습니다. 자세히 알아보려면 다음 링크를 확인하세요.