요소 애니메이션

개별 DOM 요소에 애니메이션 적용하기

Transition 예제

다양한 transition 효과를 사용하는 방법입니다:

import { transition } from '@ssgoi/react';
import { fade, scale, blur, slide, fly, rotate, bounce } from '@ssgoi/react/transitions';

// Fade 트랜지션
<div ref={transition({
  key: "fade-element",
  ...fade({ spring: { stiffness: 300, damping: 30 } })
})}>
  Fade 효과
</div>

// Scale 트랜지션
<div ref={transition({
  key: "scale-element",
  ...scale({ spring: { stiffness: 300, damping: 30 } })
})}>
  Scale 효과
</div>

// Blur 트랜지션
<div ref={transition({
  key: "blur-element",
  ...blur({ amount: 10, spring: { stiffness: 300, damping: 30 } })
})}>
  Blur 효과
</div>

// Slide 트랜지션 (방향 지정)
<div ref={transition({
  key: "slide-element",
  ...slide({ direction: 'left', spring: { stiffness: 300, damping: 30 } })
})}>
  Slide 효과
</div>

// Fly 트랜지션 (커스텀 위치)
<div ref={transition({
  key: "fly-element",
  ...fly({ x: 200, y: -50, spring: { stiffness: 300, damping: 30 } })
})}>
  Fly 효과
</div>

// Rotate 트랜지션
<div ref={transition({
  key: "rotate-element",
  ...rotate({ spring: { stiffness: 300, damping: 30 } })
})}>
  Rotate 효과
</div>

// Bounce 트랜지션
<div ref={transition({
  key: "bounce-element",
  ...bounce({ spring: { stiffness: 300, damping: 30 } })
})}>
  Bounce 효과
</div>

기본 구조

TransitionConfig 인터페이스

interface TransitionConfig {
  spring?: {
    stiffness: number; // 스프링 강성 (기본: 300)
    damping: number; // 감쇠 계수 (기본: 30)
  };
  tick?: (progress: number) => void; // in: 0→1, out: 1→0
  prepare?: (element: HTMLElement) => void; // 애니메이션 시작 전 초기 설정
  onStart?: () => void;
  onEnd?: () => void;
}

트랜지션 정의

interface Transition {
  in?: (element: HTMLElement) => TransitionConfig;
  out?: (element: HTMLElement) => TransitionConfig;
}

동작 원리

  1. 마운트 시: 요소가 DOM에 추가될 때 in 함수 실행
  2. 언마운트 시: 요소가 제거되기 전 out 함수 실행
  3. 애니메이션: 스프링 물리 엔진이 progress 생성
    • in: 0 → 1
    • out: 1 → 0
  4. tick 콜백: 매 프레임마다 호출되어 스타일 업데이트

트랜지션 프리셋

import { fade, scale /** 등등 */ } from "@ssgoi/react/transitions";

프레임워크별 사용법

import { transition } from "@ssgoi/react";

<div
  ref={transition({
    key: "unique-key",
    in: (element) => ({
      tick: (progress) => {
        element.style.opacity = progress;
        element.style.transform = `translateY(${20 * (1 - progress)}px)`;
      },
    }),
    out: (element) => ({
      tick: (progress) => {
        element.style.opacity = 1 - progress;
      },
    }),
  })}
>
  Content
</div>

Progress 동작 방식

key

  • key는 페이지 내에서 고유해야 함 (DOM이 생성되거나 삭제될 때도 애니메이션 상태를 추적할 수 있도록)
  • key를 설정하지 않으면 기본적으로 호출 위치 기반의 자동 키가 생성됨

in 애니메이션

  • progress: 0 → 1
  • 요소가 나타날 때 실행
  • 투명도 0에서 1로, 작은 크기에서 원래 크기로

out 애니메이션

  • progress: 1 → 0
  • 요소가 사라질 때 실행
  • 투명도 1에서 0으로, 원래 크기에서 작은 크기로
// 예시: in과 out의 차이
{
  in: (element) => ({
    tick: (progress) => {
      // progress: 0 → 1
      element.style.opacity = progress;  // 0 → 1
    }
  }),
  out: (element) => ({
    tick: (progress) => {
      // progress: 1 → 0
      element.style.opacity = progress;  // 1 → 0
    }
  })
}

prepare 콜백

애니메이션이 시작되기 전에 DOM 요소를 준비하는 단계입니다:

{
  in: {
    prepare: (element) => {
      // tick이 실행되기 전에 초기 상태 설정
      element.style.willChange = 'opacity, transform';
    },
    tick: (progress) => ({
      opacity: progress,
      transform: `translateY(${20 * (1 - progress)}px)`
    })
  }
}