Web Animations API — CSS 애니메이션을 JS로 제어하기
Web Animations API(WAAPI)는 CSS 애니메이션과 같은 성능을 유지하면서 자바스크립트로 동적 제어가 가능한 API입니다. CSS 키프레임의 유연함과 JS의 프로그래밍 능력을 결합한 것이라고 생각하면 됩니다.
element.animate() 기본
// CSS @keyframes와 동일한 효과
const animation = element.animate(
[
{ transform: "translateX(0)", opacity: 1 },
{ transform: "translateX(300px)", opacity: 0 },
],
{
duration: 1000, // 1초
easing: "ease-out",
fill: "forwards", // 애니메이션 후 마지막 상태 유지
}
);
키프레임 옵션
// 배열 형식 — 균등 분배
element.animate([
{ transform: "scale(1)" }, // 0%
{ transform: "scale(1.5)" }, // 50%
{ transform: "scale(1)" }, // 100%
], { duration: 500 });
// offset으로 타이밍 지정 (CSS의 % 키프레임)
element.animate([
{ transform: "translateY(0)", offset: 0 },
{ transform: "translateY(-50px)", offset: 0.3 },
{ transform: "translateY(20px)", offset: 0.7 },
{ transform: "translateY(0)", offset: 1 },
], { duration: 1000 });
// 개별 속성에 다른 이징
element.animate([
{ opacity: 0, transform: "translateY(20px)" },
{ opacity: 1, transform: "translateY(0)" },
], {
duration: 600,
easing: "ease-out",
});
애니메이션 제어
const animation = element.animate(keyframes, options);
// 재생 제어
animation.pause(); // 일시정지
animation.play(); // 재생
animation.cancel(); // 취소 (원래 상태로)
animation.finish(); // 즉시 종료
animation.reverse(); // 역방향
// 속도 제어
animation.playbackRate = 2; // 2배속
animation.playbackRate = 0.5; // 0.5배속
animation.playbackRate = -1; // 역방향 1배속
// 현재 시간 설정 (밀리초)
animation.currentTime = 500; // 500ms 지점으로 이동
// 상태 확인
console.log(animation.playState); // "running", "paused", "finished"
완료 감지
const animation = element.animate(keyframes, { duration: 1000 });
// Promise 기반
await animation.finished;
console.log("애니메이션 완료!");
// 이벤트 기반
animation.addEventListener("finish", () => {
console.log("완료");
});
animation.addEventListener("cancel", () => {
console.log("취소됨");
});
실전 — 팝업 애니메이션
function showPopup(popup) {
popup.style.display = "block";
return popup.animate([
{ opacity: 0, transform: "scale(0.8) translateY(20px)" },
{ opacity: 1, transform: "scale(1) translateY(0)" },
], {
duration: 300,
easing: "cubic-bezier(0.34, 1.56, 0.64, 1)", // 바운스 효과
fill: "forwards",
}).finished;
}
async function hidePopup(popup) {
await popup.animate([
{ opacity: 1, transform: "scale(1)" },
{ opacity: 0, transform: "scale(0.8)" },
], {
duration: 200,
easing: "ease-in",
fill: "forwards",
}).finished;
popup.style.display = "none";
}
실전 — 리스트 아이템 추가
function addListItem(list, content) {
const li = document.createElement("li");
li.textContent = content;
list.appendChild(li);
li.animate([
{ opacity: 0, transform: "translateX(-20px)", height: "0px" },
{ opacity: 1, transform: "translateX(0)", height: `${li.scrollHeight}px` },
], {
duration: 300,
easing: "ease-out",
fill: "forwards",
});
}
async function removeListItem(li) {
await li.animate([
{ opacity: 1, transform: "translateX(0)" },
{ opacity: 0, transform: "translateX(50px)" },
], {
duration: 250,
easing: "ease-in",
}).finished;
li.remove();
}
여러 애니메이션 연결
async function sequentialAnimation(element) {
// 1단계: 나타나기
await element.animate([
{ opacity: 0 }, { opacity: 1 },
], { duration: 300, fill: "forwards" }).finished;
// 2단계: 이동
await element.animate([
{ transform: "translateX(0)" }, { transform: "translateX(200px)" },
], { duration: 500, fill: "forwards" }).finished;
// 3단계: 회전
await element.animate([
{ transform: "translateX(200px) rotate(0)" },
{ transform: "translateX(200px) rotate(360deg)" },
], { duration: 400, fill: "forwards" }).finished;
}
getAnimations() — 실행 중인 애니메이션 관리
// 요소의 모든 애니메이션 가져오기
const animations = element.getAnimations();
console.log(`${animations.length}개 애니메이션 실행 중`);
// 모든 애니메이션 일시정지
animations.forEach((anim) => anim.pause());
// 문서 전체의 애니메이션
const allAnimations = document.getAnimations();
allAnimations.forEach((anim) => {
anim.playbackRate *= 2; // 모든 애니메이션 2배속
});
CSS vs WAAPI vs requestAnimationFrame
| 항목 | CSS Animation | WAAPI | requestAnimationFrame |
|---|---|---|---|
| 성능 | GPU 가속 | GPU 가속 | 메인 스레드 |
| 동적 제어 | 제한적 | 완전 제어 | 완전 제어 |
| Promise | X | O | X |
| 복잡한 로직 | X | 제한적 | O |
| 코드 양 | 적음 | 중간 | 많음 |
**기억하기 **: 간단한 애니메이션은 CSS, 동적 제어가 필요하면 WAAPI, 게임이나 물리 시뮬레이션은 requestAnimationFrame을 사용합니다. WAAPI는 CSS 애니메이션의 성능을 유지하면서 JS의 유연성을 제공하는 최적의 중간 지점입니다.
댓글 로딩 중...