스케일 애니메이션
요소의 크기를 조절하여 확대/축소 효과를 만듭니다
스케일 애니메이션
스케일(Scale) 애니메이션은 요소의 크기를 변경하여 확대되거나 축소되는 효과를 만듭니다. 주목도를 높이거나 시각적 계층을 표현할 때 효과적입니다.
기본 사용법
import { transition } from '@ssgoi/react';
import { scale } from '@ssgoi/react/transitions';
function Component() {
const [isVisible, setIsVisible] = useState(true);
return (
<div>
{isVisible && (
<div ref={transition({ key: 'scale-element', ...scale() })}>
스케일 애니메이션이 적용된 요소
</div>
)}
</div>
);
}
옵션
interface ScaleOptions {
start?: number; // 시작 크기 배율 (기본값: 0)
opacity?: number; // 시작 투명도 (기본값: 0)
axis?: 'x' | 'y' | 'both'; // 스케일 방향 (기본값: 'both')
spring?: {
stiffness?: number; // 스프링 강도 (기본값: 300)
damping?: number; // 감쇠 계수 (기본값: 30)
};
}
옵션 설명
- start: 애니메이션 시작 시 크기 (0 = 0%, 1 = 100%)
- opacity: 시작 투명도 (0-1)
- axis: 스케일이 적용될 축
'both'
: X와 Y축 모두 (기본값)'x'
: 가로 방향만'y'
: 세로 방향만
- spring: 스프링 물리 설정
사용 예시
축 방향 스케일
X축 스케일 (가로 확장)
const scaleX = scale({
axis: 'x',
spring: { stiffness: 400, damping: 35 }
});
<div ref={transition({ key: 'scale-x', ...scaleX })}>
가로로만 확장되는 요소
</div>
Y축 스케일 (세로 확장)
const scaleY = scale({
axis: 'y',
spring: { stiffness: 400, damping: 35 }
});
<div ref={transition({ key: 'scale-y', ...scaleY })}>
세로로만 확장되는 요소
</div>
부분 스케일
작은 크기에서 시작하는 효과:
const partialScale = scale({
start: 0.5, // 50% 크기에서 시작
opacity: 0.3, // 30% 투명도에서 시작
});
<div ref={transition({ key: 'partial-scale', ...partialScale })}>
절반 크기에서 시작하는 요소
</div>
바운스 효과가 있는 스케일
스프링 설정으로 바운스 효과 추가:
const bounceScale = scale({
spring: {
stiffness: 200, // 낮은 강도로 바운스
damping: 15 // 낮은 감쇠로 진동 증가
}
});
<div ref={transition({ key: 'bounce-scale', ...bounceScale })}>
통통 튀는 스케일 효과
</div>
실용적인 활용 예시
카드 호버 효과
function Card() {
const [isHovered, setIsHovered] = useState(false);
return (
<div
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{isHovered && (
<div
ref={transition({
key: 'card-hover',
...scale({ start: 0.95, opacity: 0.8 })
})}
className="absolute inset-0 bg-blue-500/20 rounded-lg"
/>
)}
<div className="p-4">카드 내용</div>
</div>
);
}
모달 등장 효과
function Modal({ isOpen, onClose }) {
return (
<>
{isOpen && (
<div className="fixed inset-0 flex items-center justify-center">
<div
ref={transition({
key: 'modal',
...scale({ start: 0.8, opacity: 0 })
})}
className="bg-white rounded-lg p-6 shadow-xl"
>
<h2>모달 제목</h2>
<p>모달 내용</p>
<button onClick={onClose}>닫기</button>
</div>
</div>
)}
</>
);
}
아이콘 애니메이션
function AnimatedIcon() {
const [isActive, setIsActive] = useState(false);
return (
<button onClick={() => setIsActive(!isActive)}>
{isActive ? (
<HeartFilledIcon
ref={transition({
key: 'heart-icon',
...scale({ start: 0, spring: { stiffness: 600, damping: 20 } })
})}
/>
) : (
<HeartOutlineIcon />
)}
</button>
);
}
성능 최적화
transform: scale()
은 GPU 가속을 사용하여 성능이 우수합니다- 레이아웃 변경을 일으키지 않아 리플로우가 발생하지 않습니다
- 많은 요소에 동시 적용 시에도 부드러운 애니메이션을 유지합니다
성능 팁
// 좋은 예: transform 사용
const goodScale = scale(); // transform: scale() 사용
// 피해야 할 예: width/height 직접 변경
const badScale = {
in: (element) => ({
tick: (progress) => {
// 리플로우 발생!
element.style.width = `${progress * 100}px`;
element.style.height = `${progress * 100}px`;
}
})
};
접근성 고려사항
<button
ref={transition({
key: 'accessible-button',
...scale({ start: 0.9 })
})}
aria-label="확대되는 버튼"
className="focus:outline-none focus:ring-2"
>
클릭하세요
</button>
권장 사용 사례
- 버튼/아이콘: 클릭 피드백이나 호버 효과
- 카드/타일: 선택 상태나 포커스 표시
- 모달/팝업: 등장과 퇴장 애니메이션
- 이미지 갤러리: 썸네일 확대 효과
- 차트/그래프: 데이터 시각화 요소의 강조