generated from gc/template-java-maven
- 디자인 시스템 가이드 문서 11개 생성 (docs/design/) - CSS 변수 토큰 시스템 (@theme + :root/.dark 전환) - cn() 유틸리티 (clsx + tailwind-merge) - Button/Badge 공통 컴포넌트 (variant/size, 다크모드 대응) - 하드코딩 Tailwind 색상 → CSS 변수 토큰 리팩토링 (30개 파일) - 차트 팔레트 다크모드 색상 업데이트 (CHART_COLORS_HEX) - 버튼 다크모드 채도/대비 강화 (primary-600 기반) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
153 lines
3.5 KiB
Markdown
153 lines
3.5 KiB
Markdown
# 모션 & 애니메이션
|
|
|
|
---
|
|
|
|
## 원칙
|
|
|
|
- 모션은 UI의 상태 변화를 명확히 전달하기 위한 수단이다.
|
|
- 불필요한 애니메이션은 사용하지 않는다.
|
|
- 모든 모션은 `prefers-reduced-motion` 미디어 쿼리를 존중한다.
|
|
|
|
---
|
|
|
|
## Duration (지속 시간)
|
|
|
|
| 이름 | 값 | Tailwind | 용도 |
|
|
|------|----|----------|------|
|
|
| instant | 0ms | — | 즉각 반응 (포커스, 선택) |
|
|
| fast | 100ms | `duration-100` | 버튼 hover, 색상 전환 |
|
|
| normal | 200ms | `duration-200` | 패널 열기, 드롭다운 |
|
|
| slow | 300ms | `duration-300` | 모달, 사이드바 슬라이드 |
|
|
| slower | 500ms | `duration-500` | 페이지 전환, 스켈레톤 |
|
|
|
|
기본값: `duration-200`. 특별한 이유 없이 300ms를 초과하지 않는다.
|
|
|
|
---
|
|
|
|
## Easing (가속도 곡선)
|
|
|
|
| 이름 | 값 | Tailwind | 용도 |
|
|
|------|----|----------|------|
|
|
| ease-out | `cubic-bezier(0, 0, 0.2, 1)` | `ease-out` | 진입 애니메이션 (요소 나타남) |
|
|
| ease-in | `cubic-bezier(0.4, 0, 1, 1)` | `ease-in` | 퇴장 애니메이션 (요소 사라짐) |
|
|
| ease-in-out | `cubic-bezier(0.4, 0, 0.2, 1)` | `ease-in-out` | 상태 전환 (toggle, expand) |
|
|
| spring | `cubic-bezier(0.34, 1.56, 0.64, 1)` | — | 강조 효과 (알림, 배지) |
|
|
|
|
기본 조합: 진입 `ease-out`, 퇴장 `ease-in`.
|
|
|
|
---
|
|
|
|
## 패턴
|
|
|
|
### Hover / Active
|
|
|
|
버튼, 카드, 링크 등 상호작용 요소.
|
|
|
|
```css
|
|
transition-colors duration-100 ease-out
|
|
```
|
|
|
|
포인터 커서 피드백:
|
|
```css
|
|
active:scale-[0.98] transition-transform duration-75
|
|
```
|
|
|
|
### 진입 (Fade + Slide)
|
|
|
|
모달, 드롭다운, Toast 등 요소가 나타날 때.
|
|
|
|
```css
|
|
/* 아래에서 위로 */
|
|
translate-y-2 opacity-0 → translate-y-0 opacity-100
|
|
transition-[transform,opacity] duration-200 ease-out
|
|
|
|
/* 위에서 아래로 (드롭다운) */
|
|
-translate-y-2 opacity-0 → translate-y-0 opacity-100
|
|
transition-[transform,opacity] duration-200 ease-out
|
|
```
|
|
|
|
### 퇴장 (Fade + Slide)
|
|
|
|
```css
|
|
translate-y-0 opacity-100 → translate-y-2 opacity-0
|
|
transition-[transform,opacity] duration-150 ease-in
|
|
```
|
|
|
|
### 사이드바 / 패널 슬라이드
|
|
|
|
```css
|
|
-translate-x-full → translate-x-0
|
|
transition-transform duration-300 ease-out
|
|
```
|
|
|
|
### 모달 배경 (Backdrop)
|
|
|
|
```css
|
|
opacity-0 → opacity-100
|
|
transition-opacity duration-200 ease-out
|
|
```
|
|
|
|
### 스켈레톤 로딩
|
|
|
|
```css
|
|
animate-pulse
|
|
```
|
|
|
|
### 회전 (로딩 스피너)
|
|
|
|
```css
|
|
animate-spin
|
|
```
|
|
|
|
### 토글 (Accordion, Expand)
|
|
|
|
높이 애니메이션은 `max-height` 트릭을 사용한다.
|
|
|
|
```css
|
|
max-h-0 overflow-hidden → max-h-screen
|
|
transition-[max-height] duration-300 ease-in-out
|
|
```
|
|
|
|
---
|
|
|
|
## prefers-reduced-motion
|
|
|
|
모든 모션은 사용자의 시스템 설정을 존중해야 한다.
|
|
|
|
### Tailwind 설정
|
|
|
|
```html
|
|
<!-- 기본 패턴 -->
|
|
<div class="transition-opacity duration-200 motion-reduce:transition-none motion-reduce:duration-0">
|
|
```
|
|
|
|
### CSS 전역 설정 (권장)
|
|
|
|
```css
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*, *::before, *::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
scroll-behavior: auto !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
### React Hook
|
|
|
|
```tsx
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
const duration = prefersReducedMotion ? 0 : 200;
|
|
```
|
|
|
|
---
|
|
|
|
## 금지 사항
|
|
|
|
- 3초 이상의 루프 애니메이션 (사용자 주의 분산)
|
|
- 화면 전체를 덮는 플래시/깜박임 효과
|
|
- 스크롤에 연동된 복잡한 패럴랙스
|
|
- `animation-duration: 0` 직접 설정 (prefers-reduced-motion 우회 금지)
|