Web Animations API(WAAPI)는 CSS 애니메이션과 같은 성능을 유지하면서 자바스크립트로 동적 제어가 가능한 API입니다. CSS 키프레임의 유연함과 JS의 프로그래밍 능력을 결합한 것이라고 생각하면 됩니다.

element.animate() 기본

JS
// CSS @keyframes와 동일한 효과
const animation = element.animate(
  [
    { transform: "translateX(0)", opacity: 1 },
    { transform: "translateX(300px)", opacity: 0 },
  ],
  {
    duration: 1000,    // 1초
    easing: "ease-out",
    fill: "forwards",  // 애니메이션 후 마지막 상태 유지
  }
);

키프레임 옵션

JS
// 배열 형식 — 균등 분배
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",
});

애니메이션 제어

JS
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"

완료 감지

JS
const animation = element.animate(keyframes, { duration: 1000 });

// Promise 기반
await animation.finished;
console.log("애니메이션 완료!");

// 이벤트 기반
animation.addEventListener("finish", () => {
  console.log("완료");
});

animation.addEventListener("cancel", () => {
  console.log("취소됨");
});

실전 — 팝업 애니메이션

JS
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";
}

실전 — 리스트 아이템 추가

JS
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();
}

여러 애니메이션 연결

JS
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() — 실행 중인 애니메이션 관리

JS
// 요소의 모든 애니메이션 가져오기
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 AnimationWAAPIrequestAnimationFrame
성능GPU 가속GPU 가속메인 스레드
동적 제어제한적완전 제어완전 제어
PromiseXOX
복잡한 로직X제한적O
코드 양적음중간많음

**기억하기 **: 간단한 애니메이션은 CSS, 동적 제어가 필요하면 WAAPI, 게임이나 물리 시뮬레이션은 requestAnimationFrame을 사용합니다. WAAPI는 CSS 애니메이션의 성능을 유지하면서 JS의 유연성을 제공하는 최적의 중간 지점입니다.

댓글 로딩 중...