Files
2nd/10_Wiki/Topics/AI_and_ML/CSS Animations.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

8.6 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-css-animations CSS Animations & Performance 10_Wiki/Topics verified self
CSS animation
transform
will-change
prefers-reduced-motion
micro-interaction
FLIP
animation performance
view transitions
none A 0.93 applied
css
animation
performance
frontend
ux
accessibility
transform
will-change
prefers-reduced-motion
view-transitions
2026-05-10 pending
language framework
CSS / JS Web Animations API / Framer Motion / GSAP

CSS Animations

📌 한 줄 통찰

"매 60 FPS 의 transform + opacity". 매 layout property 의 animate = 매 jank. 매 GPU compositor layer 의 ride. 매 modern: 매 prefers-reduced-motion + 매 View Transitions API. 매 functional > decorative.

📖 핵심

매 rendering pipeline

  1. Style → 매 CSS apply.
  2. Layout (Reflow) → 매 width / height / position 변경.
  3. Paint (Repaint) → 매 color / shadow.
  4. Composite → 매 GPU layer.

→ 매 transform + opacity 만 의 composite (skip layout, paint).

매 cheap properties (60 FPS)

  • transform: translate, scale, rotate.
  • opacity.
  • filter (some).

매 expensive

  • width, height, padding, margin.
  • top, left (use translate instead).
  • box-shadow, border-radius (some).
  • background image animation.

매 핵심 technique

transform: translate3d(0,0,0) / translateZ(0)

  • 매 GPU compositor layer 의 force.
  • 매 will-change 의 modern alternative.

will-change: transform

  • 매 hint 의 browser optimize.
  • 매 overuse 의 memory waste.
  • 매 use sparingly.

position: absolute / fixed

  • 매 reflow 의 isolate.
  • 매 sibling 의 영향 X.

CSS containment

contain: layout paint;  /* 매 reflow 의 contain */

prefers-reduced-motion

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; }
}

매 modern primitive

View Transitions API (Chrome 111+)

  • 매 same / cross-document transition.
  • 매 SPA 의 native.
  • 매 baseline 2025 시작.

CSS @starting-style

  • 매 entering element 의 initial state.

Scroll-driven animation

  • animation-timeline: scroll().
  • 매 timeline 의 expand.

CSS @scope

  • 매 scoped animation.

매 timing 의 best practice

  • Duration: 200-500 ms (UI). 매 너무 길 → 매 wait. 매 너무 짧 → 매 invisible.
  • Easing: ease-out (UI 의 보통), ease-in-out (smooth), cubic-bezier (custom).
  • Linear: 매 mechanical (loading, progress).

매 functional purpose

  1. Feedback: 매 click → 매 visual response.
  2. Continuity: 매 state change 의 explain.
  3. Hierarchy: 매 importance 의 emphasize.
  4. Spatial relation: 매 from / to.
  5. Brand personality.

매 anti-purpose

  • 매 decoration only.
  • 매 attention-seeking infinite loop.
  • 매 long entrance animation.
  • 매 intrusive auto-play.

매 accessibility

  • prefers-reduced-motion: 매 vestibular disorder.
  • aria-busy: 매 loading state.
  • 매 focus-visible 의 keep.

매 animation library

  • Web Animations API (native, modern).
  • Framer Motion (React).
  • GSAP (general, professional).
  • Motion One (lightweight).
  • Lottie (designer-friendly).
  • Auto-Animate (FLIP automation).

💻 패턴

Cheap animation (transform + opacity)

.button {
  transition: transform 200ms ease-out, opacity 200ms ease-out;
}
.button:hover {
  transform: translateY(-2px) scale(1.02);
  opacity: 0.9;
}

Avoid layout property

/* ❌ Bad — 매 reflow */
.bad {
  transition: left 300ms;
}
.bad:hover { left: 100px; }

/* ✅ Good — 매 composite only */
.good {
  transition: transform 300ms;
}
.good:hover { transform: translateX(100px); }

Reduced motion (accessibility)

.fancy-animation {
  animation: bounce 2s ease infinite;
}

@media (prefers-reduced-motion: reduce) {
  .fancy-animation {
    animation: none;
  }
  
  /* 매 essential 의 keep, fancy 만 의 remove */
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

View Transitions API

/* Browser-side */
@view-transition {
  navigation: auto;  /* 매 same-document SPA */
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 250ms;
}
// 매 imperative
async function navigate() {
  if (!document.startViewTransition) {
    updateDOM();
    return;
  }
  document.startViewTransition(() => updateDOM());
}

Scroll-driven animation

@keyframes fade-in {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

.section {
  animation: fade-in 1s linear;
  animation-timeline: view();
  animation-range: entry 0% cover 30%;
}

Web Animations API (JS)

const card = document.querySelector('.card');

const anim = card.animate(
  [{ transform: 'translateY(20px)', opacity: 0 },
   { transform: 'translateY(0)', opacity: 1 }],
  { duration: 300, easing: 'ease-out', fill: 'forwards' },
);

await anim.finished;

FLIP technique (smooth list reorder)

function flipReorder(items, mutate) {
  // 1. First — measure
  const first = new Map();
  items.forEach(el => first.set(el, el.getBoundingClientRect()));
  
  // 2. Last — apply mutation
  mutate();
  
  // 3. Invert + Play
  items.forEach(el => {
    const last = el.getBoundingClientRect();
    const dx = first.get(el).left - last.left;
    const dy = first.get(el).top - last.top;
    
    el.animate(
      [{ transform: `translate(${dx}px, ${dy}px)` }, { transform: 'none' }],
      { duration: 300, easing: 'cubic-bezier(0.2, 0, 0.2, 1)' },
    );
  });
}

Performance: pause off-screen

.spinner { animation: spin 2s linear infinite; }
.spinner.paused { animation-play-state: paused; }
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    entry.target.classList.toggle('paused', !entry.isIntersecting);
  });
});
document.querySelectorAll('.spinner').forEach(el => observer.observe(el));

Framer Motion (React)

import { motion, AnimatePresence } from 'framer-motion';

<AnimatePresence>
  {isOpen && (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -20 }}
      transition={{ duration: 0.2, ease: 'easeOut' }}
    >
      Content
    </motion.div>
  )}
</AnimatePresence>

Performance debugging (Chrome DevTools)

1. Chrome DevTools → Performance tab → Record.
2. Look for:
   - Long tasks (>50ms)
   - Layout shift count
   - Paint flashing (Rendering tab)
   - FPS drop
3. Layer borders enable: Rendering → Layer borders.

🤔 결정 기준

상황 Approach
Hover effect CSS transition (transform, opacity)
Modal entrance CSS animation + scale + opacity
Page transition (SPA) View Transitions API
List reorder FLIP technique
Scroll animation scroll-driven (modern) or IO + class
Designer-driven Lottie (designer-friendly)
Complex sequence GSAP / Framer Motion
Loading CSS animation + accessibility

기본값: CSS transition + transform + opacity. 매 prefers-reduced-motion. 매 functional only.

🔗 Graph

🤖 LLM 활용

언제: 매 frontend animation. 매 micro-interaction. 매 UX polish. 매 accessibility audit. 언제 X: 매 server-side. 매 non-visual.

안티패턴

  • top / left animate: 매 reflow.
  • width / height animate: 매 reflow.
  • No prefers-reduced-motion: 매 accessibility violation.
  • will-change overuse: 매 memory waste.
  • Long entrance (>1 sec): 매 user wait.
  • Auto-play heavy animation: 매 mobile data + battery.
  • Off-screen infinite loop: 매 CPU 의 burn.

🧪 검증 / 중복

🕓 Changelog

날짜 변경
2026-04-26 Auto-mapped
2026-05-08 Phase 1
2026-05-10 Manual cleanup — pipeline + cheap/expensive + view-transitions + 매 CSS / FLIP / Framer code