f8b21af4be
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>
8.6 KiB
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 |
|
none | A | 0.93 | applied |
|
2026-05-10 | pending |
|
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
- Style → 매 CSS apply.
- Layout (Reflow) → 매 width / height / position 변경.
- Paint (Repaint) → 매 color / shadow.
- 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
- Feedback: 매 click → 매 visual response.
- Continuity: 매 state change 의 explain.
- Hierarchy: 매 importance 의 emphasize.
- Spatial relation: 매 from / to.
- 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
- 부모: Web-Performance · Frontend
- 변형: Transform · Will-Change · View-Transitions
- 응용: Web-Animations-API · Framer-Motion · GSAP
- Adjacent: Reflow-Repaint · GPU-Acceleration · Accessibility (A11y) · Baseline-Project
🤖 LLM 활용
언제: 매 frontend animation. 매 micro-interaction. 매 UX polish. 매 accessibility audit. 언제 X: 매 server-side. 매 non-visual.
❌ 안티패턴
top/leftanimate: 매 reflow.width/heightanimate: 매 reflow.- No
prefers-reduced-motion: 매 accessibility violation. will-changeoveruse: 매 memory waste.- Long entrance (>1 sec): 매 user wait.
- Auto-play heavy animation: 매 mobile data + battery.
- Off-screen infinite loop: 매 CPU 의 burn.
🧪 검증 / 중복
- Verified (web.dev animation, MDN, Paul Lewis 의 Aerotwist).
- 신뢰도 A.
- Related: Web-Performance · Accessibility (A11y) · Baseline-Project · FLIP-Technique.
🕓 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 |