Animation

Animation

CSS 애니메이션을 사용해 Chakra UI 컴포넌트를 애니메이션하는 방법을 다루는 개념 문서예요. 마운트/언마운트 진입·퇴장 애니메이션을 다룰 수 있어요.

출처: 문서

본문

Chakra UI 컴포넌트를 애니메이션할 때는 CSS 애니메이션을 사용하는 것을 권장해요. 이 방식은 성능이 좋고 직관적이며 유연성이 뛰어나요.

컴포넌트의 마운트(mounting)와 언마운트(unmounting) 단계를 모두 더 잘 제어하며 애니메이션할 수 있어요.

진입 애니메이션 (Enter animation)

디스클로저 컴포넌트(popover, dialog)가 열리면 data-state 속성이 open으로 설정돼요. 이는 data-state=open에 매핑되며 _open 의사 prop으로 스타일링할 수 있어요.

<Box
  data-state="open"
  _open={{
    animation: "fade-in 300ms ease-out",
  }}
>
  This is open
</Box>

다음은 keyframes를 사용해 페이드인 애니메이션을 만드는 예시예요:

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

퇴장 애니메이션 (Exit animation)

디스클로저 컴포넌트(popover, dialog)가 닫히면 data-state 속성이 closed로 설정돼요. 이는 data-state=closed에 매핑되며 _closed 의사 prop으로 스타일링할 수 있어요.

<Box
  data-state="closed"
  _closed={{
    animation: "fadeOut 300ms ease-in",
  }}
>
  This is closed
</Box>

다음은 keyframes를 사용해 페이드아웃 애니메이션을 만드는 예시예요:

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

애니메이션 구성 (Composing animations)

animationName prop을 사용하면 여러 애니메이션을 함께 구성할 수 있어요. 이렇게 하면 여러 keyframes로 복잡한 애니메이션을 쉽게 만들 수 있어요.

<Box
  data-state="open"
  _open={{
    animationName: "fade-in, scale-in",
    animationDuration: "300ms",
  }}
  _closed={{
    animationName: "fade-out, scale-out",
    animationDuration: "120ms",
  }}
>
  This is a composed animation
</Box>

모션 줄이기 (Reduced motion)

내장 컴포넌트 애니메이션은 사용자의 prefers-reduced-motion 설정과 관계없이 재생돼요. 축소 모션을 선호하는 사용자를 위해 진입/퇴장 애니메이션을 비활성화하려면 globalCss 설정에 이 규칙을 추가해 주세요:

import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"

const config = defineConfig({
  globalCss: {
    '[data-state="open"], [data-state="closed"]': {
      _motionReduce: {
        animationDuration: "1ms !important",
      },
    },
  },
})

export const system = createSystem(defaultConfig, config)

이렇게 하면 축소 모션이 활성화되었을 때 모든 디스클로저 컴포넌트(dialog, drawer, menu, popover, tooltip 등)의 진입/퇴장 애니메이션이 1ms로 단축돼요.

몇 가지 알아두면 좋은 세부 사항이 있어요:

  • data-state="open"과 data-state="closed"로 범위를 한정하세요. 모든 요소를 대상으로 하는 광범위한 규칙은 루핑 애니메이션(Spinner, Skeleton, 불확정 Progress)까지 축소시켜 깜빡임으로 만들기 때문이에요. 로딩 인디케이터는 필수 모션으로 간주되므로 그대로 실행되게 두는 것이 좋아요.
  • animation: none도 작동해요. 표시 로직이 이를 감지해 퇴장 컴포넌트를 즉시 언마운트해요. 1ms 지속 시간을 권장하는 이유는, 이를 감지하는 커스텀 코드를 위해 animationend 이벤트가 계속 발생하도록 유지하기 때문이에요.
  • !important가 필요해요. 규칙이 컴포넌트 레시피보다 낮은 CSS 레이어에 있기 때문이에요.

커스텀 애니메이션을 만들 때는 _motionReduce 조건을 사용해 축소 모션 대안을 제공해 주세요:

<Box
  data-state="open"
  _open={{ animationName: "slide-from-bottom, fade-in" }}
  _motionReduce={{ animationName: "fade-in" }}
>
  Slides on screen, but only fades for reduced motion users
</Box>

더 알아보기 (Learn more)

Chakra UI에서 애니메이션을 다루는 더 자세한 내용은 공식 문서를 확인해 보세요.