[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,74 +1,332 @@
|
||||
---
|
||||
id: wiki-2026-0508-css-animations
|
||||
title: CSS Animations
|
||||
title: CSS Animations & Performance
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [CSS animation, transform, will-change, prefers-reduced-motion, micro-interaction, FLIP, animation performance, view transitions]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.93
|
||||
verification_status: applied
|
||||
tags: [css, animation, performance, frontend, ux, accessibility, transform, will-change, prefers-reduced-motion, view-transitions]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: CSS / JS
|
||||
framework: Web Animations API / Framer Motion / GSAP
|
||||
---
|
||||
|
||||
# [[CSS Animations|CSS Animations]]
|
||||
# CSS Animations
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
CSS 애니메이션은 UI/UX에서 사용자와 시스템 간의 상호작용을 강화하고 시각적 피드백을 제공하며, 시스템 상태나 계층 구조를 명확히 하는 데 사용되는 기술이다 [1, 2]. 단순한 시각적 장식이 아닌 인지 부하를 줄이고 사용성을 높이는 기능적 목적을 가지며 [2-4], 실무적으로는 브라우저의 리플로우(Reflow)와 리페인트(Repaint)를 최소화하여 60FPS의 렌더링 성능을 유지하고 유지보수가 용이하도록 설계되어야 한다 [5, 6].
|
||||
## 📌 한 줄 통찰
|
||||
> **"매 60 FPS 의 transform + opacity"**. 매 layout property 의 animate = 매 jank. 매 GPU compositor layer 의 ride. 매 modern: 매 `prefers-reduced-motion` + 매 View Transitions API. 매 functional > decorative.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **애니메이션의 기능적 역할 및 UX 원칙**
|
||||
애니메이션은 단순히 화면을 꾸미는 것이 아니라, 사용자에게 즉각적인 피드백을 주고 주의를 유도하며 원인과 결과의 관계를 설명하는 기능적 도구이다 [1, 2, 4]. 호버(Hover) 효과, 버튼 클릭 시의 마이크로 인터랙션, 로딩 상태 진행 표시, 부드러운 화면 상태 전환 등에 주로 활용된다 [7-10]. 애니메이션의 지속 시간은 사용자 대기 시간을 줄이기 위해 200ms에서 500ms 사이로 짧게 유지하는 것이 좋으며, 기계적인 선형 움직임 대신 `ease-in-out`과 같은 이징(Easing) 함수를 활용해 물리 법칙에 기반한 자연스러운 움직임을 설계해야 한다 [11-14].
|
||||
## 📖 핵심
|
||||
|
||||
* **성능 저하를 유발하는 안티 패턴 ([[Reflow & Repaint|Reflow & Repaint]])**
|
||||
프론트엔드 실전 설계에서 애니메이션 성능은 변경되는 CSS 속성에 크게 좌우된다 [15, 16]. `width`, `height`, `margin`, `padding`, `top`, `left` 등의 레이아웃 속성을 애니메이션 처리하면 브라우저의 리플로우(Reflow)와 리페인트(Repaint)가 지속해서 발생하여 애니메이션이 끊기는 현상(Jank)이 발생한다 [5, 6, 15, 17]. 또한 `box-shadow`, `filter`, `border-radius` 및 크고 복잡한 배경 이미지의 애니메이션은 렌더링 자원 소모가 크기 때문에 주의가 필요하다 [16, 18]. 동시에 너무 많은 요소를 애니메이션하거나 불필요한 무한 루프(`infinite`)를 적용하는 것도 브라우저 성능을 크게 저하하는 원인이 된다 [19, 20].
|
||||
### 매 rendering pipeline
|
||||
1. **Style** → 매 CSS apply.
|
||||
2. **Layout (Reflow)** → 매 width / height / position 변경.
|
||||
3. **Paint (Repaint)** → 매 color / shadow.
|
||||
4. **Composite** → 매 GPU layer.
|
||||
|
||||
* **유지보수 가능하고 확장성 있는 성능 최적화 전략**
|
||||
부드럽고 렌더링 비용이 적은 애니메이션을 구현하기 위해서는 레이아웃에 영향을 주지 않는 `transform` (예: `translateZ()`, `scale()`)과 `opacity` 속성을 적극 활용해야 한다 [16, 21-23]. 이러한 속성들은 브라우저 렌더링 파이프라인에서 레이아웃과 페인트 단계를 건너뛰고 컴포지팅(Compositing) 단계만 거치게 되며, GPU 하드웨어 가속을 받아 모바일 기기에서도 뛰어난 성능을 보장한다 [16, 23, 24].
|
||||
또한 `position: absolute`나 `position: fixed` 요소에 애니메이션을 적용하면 DOM 트리의 다른 요소에 미치는 리플로우 영향을 차단할 수 있다 [24-26]. 애니메이션이 확정된 요소에는 `will-change` 속성을 부여해 브라우저가 최적화를 미리 준비하도록 힌트를 줄 수 있으나, 과도하게 사용할 경우 오히려 성능을 저하시키므로 최소화하여 사용해야 한다 [27, 28].
|
||||
→ 매 transform + opacity 만 의 composite (skip layout, paint).
|
||||
|
||||
* **접근성과 실무 환경에서의 제어**
|
||||
보이지 않는 요소의 무한 루프 애니메이션은 시스템 리소스를 고갈시키므로, `animation-play-[[State|State]]`를 사용해 화면 이탈 시 애니메이션을 일시 정지시키는 제어가 필요하다 [5, 20]. 아울러, 과도한 모션은 일부 사용자에게 어지러움을 유발할 수 있으므로 웹 콘텐츠 접근성 지침(WCAG)에 따라 `prefers-reduced-motion` 미디어 쿼리를 활용해 애니메이션을 선택적으로 줄이거나 제거할 수 있는 접근성 장치를 반드시 마련해야 한다 [11, 29, 30].
|
||||
### 매 cheap properties (60 FPS)
|
||||
- ✅ `transform`: translate, scale, rotate.
|
||||
- ✅ `opacity`.
|
||||
- ✅ `filter` (some).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Reflow and Repaint|Reflow and Repaint]], Hardware Acceleration (GPU), Micro-interactions, [[Accessibility|Accessibility]] (prefers-reduced-motion)
|
||||
- **Projects/Contexts:** [[Large Frontend Projects|Large Frontend Projects]], [[Performance Optimization|Performance Optimization]]
|
||||
- **Contradictions/Notes:** 무한 루프 애니메이션과 화려한 모션은 인터페이스에 활력을 줄 수 있지만 시스템 리소스를 크게 소모하며, 전정기관 장애가 있는 사용자에게 위험할 수 있습니다 [11, 20]. 따라서 실무 환경에서는 애니메이션 적용을 필수적인 기능과 마이크로 인터랙션으로 제한하고, 화면에서 벗어났을 때 정지시키거나(`animation-play-state`) 사용자의 환경 설정에 따라 모션을 줄이는(`prefers-reduced-motion`) 방어적 설계가 동반되어야 합니다 [20, 29, 30].
|
||||
### 매 expensive
|
||||
- ❌ `width`, `height`, `padding`, `margin`.
|
||||
- ❌ `top`, `left` (use translate instead).
|
||||
- ❌ `box-shadow`, `border-radius` (some).
|
||||
- ❌ background image animation.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
### 매 핵심 technique
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
#### `transform: translate3d(0,0,0)` / `translateZ(0)`
|
||||
- 매 GPU compositor layer 의 force.
|
||||
- 매 will-change 의 modern alternative.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
#### `will-change: transform`
|
||||
- 매 hint 의 browser optimize.
|
||||
- 매 overuse 의 memory waste.
|
||||
- 매 use sparingly.
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
#### `position: absolute / fixed`
|
||||
- 매 reflow 의 isolate.
|
||||
- 매 sibling 의 영향 X.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
#### CSS containment
|
||||
```css
|
||||
contain: layout paint; /* 매 reflow 의 contain */
|
||||
```
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
#### `prefers-reduced-motion`
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* { animation-duration: 0.01ms !important; }
|
||||
}
|
||||
```
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
### 매 modern primitive
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
#### View Transitions API (Chrome 111+)
|
||||
- 매 same / cross-document transition.
|
||||
- 매 SPA 의 native.
|
||||
- 매 baseline 2025 시작.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
#### CSS @starting-style
|
||||
- 매 entering element 의 initial state.
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
#### Scroll-driven animation
|
||||
- 매 `animation-timeline: scroll()`.
|
||||
- 매 timeline 의 expand.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
#### CSS @scope
|
||||
- 매 scoped animation.
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
### 매 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)
|
||||
```css
|
||||
.button {
|
||||
transition: transform 200ms ease-out, opacity 200ms ease-out;
|
||||
}
|
||||
.button:hover {
|
||||
transform: translateY(-2px) scale(1.02);
|
||||
opacity: 0.9;
|
||||
}
|
||||
```
|
||||
|
||||
### Avoid layout property
|
||||
```css
|
||||
/* ❌ 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)
|
||||
```css
|
||||
.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
|
||||
```css
|
||||
/* Browser-side */
|
||||
@view-transition {
|
||||
navigation: auto; /* 매 same-document SPA */
|
||||
}
|
||||
|
||||
::view-transition-old(root),
|
||||
::view-transition-new(root) {
|
||||
animation-duration: 250ms;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
// 매 imperative
|
||||
async function navigate() {
|
||||
if (!document.startViewTransition) {
|
||||
updateDOM();
|
||||
return;
|
||||
}
|
||||
document.startViewTransition(() => updateDOM());
|
||||
}
|
||||
```
|
||||
|
||||
### Scroll-driven animation
|
||||
```css
|
||||
@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)
|
||||
```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)
|
||||
```js
|
||||
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
|
||||
```css
|
||||
.spinner { animation: spin 2s linear infinite; }
|
||||
.spinner.paused { animation-play-state: paused; }
|
||||
```
|
||||
|
||||
```js
|
||||
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)
|
||||
```jsx
|
||||
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
|
||||
- 부모: [[CSS]] · [[Web-Performance]] · [[Frontend]]
|
||||
- 변형: [[Transform]] · [[Opacity]] · [[Will-Change]] · [[View-Transitions]] · [[Scroll-Driven-Animation]]
|
||||
- 응용: [[Web-Animations-API]] · [[Framer-Motion]] · [[GSAP]] · [[Lottie]]
|
||||
- Adjacent: [[Reflow-Repaint]] · [[GPU-Acceleration]] · [[Accessibility]] · [[Baseline-Project]]
|
||||
|
||||
## 🤖 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.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (web.dev animation, MDN, Paul Lewis 의 Aerotwist).
|
||||
- 신뢰도 A.
|
||||
- Related: [[Web-Performance]] · [[Accessibility]] · [[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 |
|
||||
|
||||
Reference in New Issue
Block a user