애니메이션
인터페이스에서 모션은 무슨 일이 일어났는지 설명합니다: 요소가 어디서 왔는지, 어디로 갔는지, 프레스가 등록되었는지. 그렇지 않은 모든 것은 장식이며, 장식에는 작은 예산이 할당됩니다. 이 스킬은 그 예산을 정확하게 사용하는 데 도움을 줍니다: 이 스킬이 없으면 모델은 모든 것을 동일한 fade-up으로 애니메이션 처리합니다.
이 스킬은 독립적으로 사용 가능합니다. ui-ux (스타일 및 인터페이스 규칙)와 front (코드 및 스택)가 함께 설치되면 상호 보완됩니다.
세 가지 질문
- 이 모션의 목적은 무엇인가요? 액션에 대한 피드백, 상태 간의 연결, 한 가지 중요한 것에 주목 유도, 브랜드의 특성. 답이 없다면 애니메이션을 사용하지 마세요.
- 사용자가 이를 얼마나 자주 보게 될까요? 예산은 이 답변에 따라 달라집니다 (다음 섹션 참조).
- 프로젝트에 이미 무엇이 있나요? 사용 중인 지속 시간, 곡선 및 애니메이션 라이브러리를 확인하고 같은 맥락으로 계속 진행하세요. 단 하나의 효과를 위해 새 라이브러리를 도입하는 것은 거의 항상 실수입니다.
적절한 애니메이션의 양
주요 규칙: 행동이 빈번할수록 애니메이션은 줄어듭니다. 첫 번째 보기에는 환상적이지만 백 번째에는 짜증을 유발합니다.
| 사용자가 보는 빈도 | 수행할 작업 |
|---|---|
| 하루 수백 번 (단축키, 명령 팔레트, 탭 전환) | 애니메이션 없음 |
| 하루 수십 번 (메뉴, 툴팁, 호버) | 매우 빠르게, 최대 150 ms, 또는 애니메이션 없음 |
| 가끔 (대화상자, 사이드 패널, 알림) | 일반적인 200–300 ms 전환 |
| 드물게 또는 한 번 (온보딩, 성공 화면, 랜딩 페이지의 첫 화면) | 표현력 있게 가능 |
프로젝트 유형별 수준:
- 앱 (매일 사용): 절제됨. 제어 상태, 레이어 진입 및 이탈, 부드러운 레이아웃 변경. 모든 것이 300 ms 미만. 사용자 액션 없이 움직이는 것은 없습니다.
- 쇼케이스 (랜딩 페이지, 웹사이트, 프로모션): 눈에 띔. 첫 화면의 하나의 조율된 순간, 스크롤에 따라 나타나는 블록, 호버 시 살아있는 디테일. 나머지는 조용하게.
화면당 하나의 표현적인 순간, 다른 곳은 모두 조용하게. 모든 것에 동시에 애니메이션을 적용하는 것은 템플릿의 신호입니다. 애니메이션이 전혀 없는 것과 마찬가지로.
애니메이션하지 말아야 할 것: 키보드로 트리거된 작업, 테마 전환, 컨텍스트 메뉴, 사용자가 연속으로 여러 번 수행하는 모든 것.
기본 취향
스킬 소유자는 이 섹션을 자신의 선호도에 맞게 편집할 수 있습니다. 현재 요청에서 사용자의 말이 우선합니다.
쇼케이스 표면에서 환영하는 것:
- 스크롤 시 나타나기(Reveal on scroll) — 섹션과 큰 객체가 스크롤될 때 부드럽게 나타납니다. 한 번, 반복 없이.
- 스크롤 연결 장면(Scroll-linked scenes) — 스크롤이 애니메이션을 구동하고 제품에 대해 설명하는 고정된 섹션. 페이지당 하나 또는 두 개; 스크롤 자체는 일반적으로 유지되며, 속도와 방향은 절대 가로채지 않습니다.
명시적으로 요청하지 않는 한 사용하지 마세요:
- 글로우 및 그라디언트 테두리 — 반짝이는 외곽선, 네온 글로우, 애니메이션 그라디언트 배경. 강조는 모션과 타이포그래피에서 오며, 빛에서 오는 것이 아닙니다.
라이브러리: CSS 우선; React에서 충분하지 않을 때는 Motion; 복잡한 스크롤 장면에서만 GSAP. 자세한 내용은 references/tools.md 참조.
모션의 특성은 '연결되고 정확함'입니다.
- 앱 내부의 흐름. 화면이 서로 교체되기보다는 녹아듭니다: 하나의 '히어로' 객체가 모든 단계를 통과하고, 텍스트가 블러를 통해 텍스트로 변하며, 변경된 것만 변경되고, 새 레이어는 그 소스에서 자랍니다. 작업에 화면이나 상태의 시퀀스가 있다면, 먼저
references/continuity.md를 읽고 히어로를 지정하세요. - 랜딩 페이지 및 웹사이트. 사이트 전체에 하나의 곡선을 사용하며, 날카로운 시작과 길고 부드러운 감속, 바운스 없음; 헤드라인이 단어별로 조립됨; 큰 것들이 블러에서 나타남; 스크롤 시 하나의 텍스트 장면; 모든 것이 CSS로. 정확한 값이 포함된 레시피는
references/showcase-recipes.md참조.
공통점: 블러와 불투명도를 함께 전환의 재료로 사용, 진입과 이탈이 겹침 대기열 대신, 바운스 없음, 그리고 일관된 곡선 하나. 프로젝트 스타일이 다른 특성(터미널, 레트로)을 요구하는 경우, references/patterns.md의 표를 참조하세요.
지속 시간
| 대상 | 지속 시간 |
|---|---|
| 프레스, 호버, 토글 자체에 대한 응답 | 100–150 ms |
| 툴팁, 드롭다운 메뉴, 작은 진입 | 150–200 ms |
| 대화상자, 패널, 시트 | 200–300 ms |
| 액션에 응답하는 콘텐츠 변경 (가격, 카운터, 차트) | 300–500 ms |
| 페이지 전환, 큰 레이아웃 변경 | 300–500 ms |
| 쇼케이스 표면의 장식 장면, 사용자 개입 없음 | 최대 800–1000 ms |
- 이탈은 진입보다 약 1/3 짧습니다. 떠나는 것은 더 이상 흥미롭지 않습니다.
- 경로가 길고 영역이 클수록 지속 시간이 깁니다. 작은 요소가 400 ms이면 느리게 보입니다.
- 규칙이 중복되면 더 짧은 쪽이 우선합니다. 컨트롤 자체는 항상 100–150 ms 내에 응답하며, 변경된 사항은 더 오래 걸릴 수 있지만 사용자가 다시 행동하기 위해 애니메이션이 끝날 때까지 기다릴 필요가 없어야 합니다.
곡선과 스프링
- 진입 — ease-out: 빠른 시작과 부드러운 정지로 반응성이 느껴집니다.
- 이탈 — 또한 ease-out, 그러나 더 짧습니다. 일부 디자인 시스템은 이탈에 가속 곡선을 사용하지만, 느린 시작이 지연처럼 느껴지므로 여기서는 사용하지 않습니다; 스킬 소유자는 이 규칙을 변경할 수 있습니다.
- 화면을 가로질러 한 지점에서 다른 지점으로 이동 — ease-in-out.
- 선형 — 연속적인 모션에만 사용: 회전 인디케이터, 마키, 진행률.
기본 토큰:
:root {
--ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* 주요 곡선: 날카로운 시작, 긴 감속 */
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
--duration-fast: 160ms; /* 응답: 색상, 불투명도 */
--duration-base: 300ms; /* 레이어, 컨트롤의 배경 및 그림자 */
--duration-slow: 450ms; /* 콘텐츠가 콘텐츠로 녹아듦 */
--duration-reveal: 800ms; /* 쇼케이스 표면에서 블록 나타나기 */
}
프로젝트 전체에 하나의 곡선 사용: 전환의 모든 부분이 동일한 곡선을 사용하면 하나의 움직임으로 읽힙니다. 이 곡선을 사용하면 응답이 200–450 ms 동안 지속되어도 여전히 즉각적으로 느껴집니다. 대부분의 변화가 처음 100 ms 내에 발생하기 때문입니다.
스프링은 제스처가 모션을 구동하거나 애니메이션이 중간에 중단될 수 있을 때(드래그, 시트, 목록 재정렬) 곡선보다 뛰어납니다: 속도를 유지하고 갑작스러운 움직임이 없습니다. 바운스는 이동 및 크기 조정에만 사용하며, 색상과 불투명도에는 항상 0입니다. 눈에 띄는 바운스는 장난기 있는 스타일에 적합하며 작업 도구에서는 짜증을 유발합니다.
실행 규칙
transform과opacity를 애니메이션 처리하세요. 너비, 높이, 여백 및 위치는 레이아웃 재계산을 유발하고 버벅임을 초래합니다. 크기를 변경하려면scale, FLIP 기법 또는 라이브러리의 레이아웃 애니메이션을 사용하세요.- 블러는 허용된 예외입니다.
filter: blur()를 최대 12px까지 불투명도와 함께 사용하는 것이 전환의 특징적인 재료이지만, 비용이 더 많이 듭니다: 작은 블록(헤딩, 그림, 아이콘, 카드)에만 적용하고, 전체 화면에는 절대 적용하지 말며, 휴대폰에서 테스트하세요. - 진입과 이탈은 겹칩니다. 떠나는 것과 도착하는 것이 지속 시간의 30–50% 동안 공존합니다. '먼저 사라지고, 그다음 나타나는' 대기열은 연결을 끊고 시간을 두 배로 만듭니다.
- 변경된 부분만 움직입니다. 변경되지 않은 것(숫자, 단어, 아이콘)은 제자리에 있습니다.
scale(0)에서 시작하지 마세요. 실제로 어떤 것도 한 점에서 나타나지 않습니다: 불투명도와 함께 0.9–0.96에서 시작하세요.transform-origin은 소스에 위치합니다. 메뉴는 버튼에서 자라나며, 중앙에서 자라지 않습니다.- 프레스:
:active에서scale(0.97)은 물리적 버튼의 느낌을 줍니다. - 중단 가능성.
@keyframes대신transition으로 대화형 모션을 구축하세요: 전환은 중간에 반전될 수 있지만, keyframes는 불가능합니다. - 역할이 먼저, 타이밍은 그다음. 하나의 이벤트에 응답하여 여러 요소가 움직일 때, 단일 리더를 지정하세요; 나머지는 지원, 장식 또는 정적입니다. 두 명의 리더는 애니메이션 문제가 아니라 레이아웃 문제입니다.
- 컨테이너당 하나의 진입. 패널이 슬라이드인되었다면, 그 콘텐츠는 이미 그곳에 있습니다: 부모의 진입 위에 자식의 지연(stagger)을 추가하지 마세요.
- 떠나는 것은 즉시 공간을 비웁니다. 따라서 주변 요소가 사라지는 동안, 사라진 후가 아니라, 닫힙니다.
- 이탈은 진입을 반영하며 동시에 발생합니다. 오른쪽에서 들어온 것은 오른쪽으로 떠납니다; 그룹은 역방향 지연 없이 동시에 사라집니다.
- 방향은 의미를 따릅니다: '앞으로'는 오른쪽에서 진입하고, '뒤로'는 왼쪽에서 진입합니다.
- 지연(Stagger): 요소 간 30–80 ms 간격, 전체 캐스케이드는 300–400 ms를 넘지 않음; 여섯 번째 또는 일곱 번째 요소 이후 나머지는 함께 나타납니다. 쇼케이스의 첫 화면에서 간격은 100–150 ms까지 올라갈 수 있습니다.
- 제스처는 스프링을 사용하며 절대 차단하지 않습니다. 요소는 손가락을 일대일로 따라가며, 중간에 잡을 수 있고, 놓은 후 제스처의 속도를 이어받습니다. 바운스는 던진 후에만 허용됩니다.
- 툴팁: 첫 번째 툴팁 전에 지연, 동일한 그룹의 다음 툴팁은 즉시 애니메이션 없이 나타납니다.
- 스크롤 시 나타나기는 한 번 발생합니다. 매번 숨겨졌다가 다시 나타나는 블록은 피로를 줍니다.
- 정지 상태의 페이지는 완전합니다. 콘텐츠가 스크립트 실행 여부에 의존해서는 안 됩니다: 숨겨진 시작 상태는 애니메이션이 활성화된 경우에만 설정되며, 기본 스타일에는 절대 설정되지 않습니다. 그렇지 않으면 스크립트가 실패할 때, 미리보기 및 스크린샷에서 사용자는 빈 화면을 보게 됩니다.
- 호버는 한 가지 속성만 변경합니다. 크기 조정, 들어올리기 및 그림자를 동시에 변경하지 마세요.
will-change— 드물게, 그리고 애니메이션 기간 동안만 사용하며, 모든 것에 사용하지 마세요.
접근성
이는 선택 사항이 아닙니다: 화면의 모션은 일부 사람들에게 어지러움과 메스꺼움을 유발합니다.
prefers-reduced-motion: reduce: 움직임, 크기 조정, 회전, 패럴랙스 및 자동 재생을 제거하세요; 불투명도와 색상의 부드러운 변경은 유지하세요. 모든 것을 완전히 끄면 사용자의 피드백을 빼앗게 됩니다. 가장 신뢰할 수 있는 접근 방식은 허용된 경우에만 모션을 선언하는 것입니다:
.card { transition: opacity var(--duration-base) var(--ease-out), background-color var(--duration-fast); }
@media (prefers-reduced-motion: no-preference) {
.card { transition-property: opacity, background-color, transform; }
.card:hover { transform: translateY(-2px); }
}
- 5초 이상 자체적으로 움직이는 모든 것(마키, 캐러셀, 배경 비디오)에는 일시 정지 버튼이 있어야 합니다 — WCAG 2.2.2 요구 사항.
- 초당 3회 이상 깜빡이는 것은 없습니다.
- 넓은 영역의 모션(패럴랙스, 배경 크기 조정)은 작은 진폭으로 유지하세요.
- 애니메이션 텍스트는 스크린 리더가 읽을 수 있어야 합니다: 문자별 분할에는 전체 구문이 포함된
aria-label을, 조각에는aria-hidden을 제공하세요.
검증
- 코드에서뿐만 아니라 브라우저에서 애니메이션을 확인하세요; 직접 확인할 수 없다면 사용자에게 라이브로 검증되지 않았음을 알리세요.
- 개발자 도구에서 4–10배 느리게 실행하세요: 버벅임, 잘못된 성장 원점 및 불필요한 속성이 드러납니다.
- 여러 번 빠르게 연속으로 프레스하세요: 애니메이션이 중단되고 반전되어야 하며, 대기열에 쌓이지 않아야 합니다.
- 시스템에서 '동작 줄이기'를 켜고 인터페이스가 여전히 작동하고 이해 가능한지 확인하세요.
- 스크롤 직후 찍은 스크린샷은 블록이 아직 나타나지 않은 빈 공간을 보여줄 수 있습니다 — "정지 상태의 페이지는 완전합니다" 규칙을 확인해야 하는 이유입니다.
검토 모드
기존 애니메이션을 평가하거나 수정하라는 요청을 받으면 결과를 표로 보고하세요:
| 위치 | 이전 | 이후 | 이유 |
|---|---|---|---|
Modal.tsx:18 | scale(0) → 1, 500 ms, ease-in | scale(0.96) + opacity, 220 ms, ease-out | 한 점에서 나타나고 지연됨 |
참조 파일
references/continuity.md— 연결된 애니메이션: 흐름의 히어로, 서로 녹아드는 화면, 숫자가 한 자리씩 변경됨, 스크롤 시 축소; 기술 및 웹에서 구축하는 방법. 화면이나 상태의 시퀀스가 있는 경우 읽으세요.references/choreography.md— 하나의 이벤트에 반응하는 요소 그룹: 역할(리드, 지원, 장식, 정적), 쌍 내 관계(함께, 겹침, 시퀀스, 운반), 지연, 방향, 이탈, 중단. 하나 이상의 요소가 움직일 때마다 읽으세요.references/gestures.md— 드래그, 스와이프 및 던져지는 모든 것: 손가락 추적, 중단 가능성, 스프링, 속도 전달, 운동량 투영, 부드러운 경계. 시트, 캐러셀, 슬라이더, 드래그 앤 드롭에 대해 읽으세요.references/showcase-recipes.md— 정확한 값이 포함된 랜딩 페이지 레시피: 단어별 헤드라인, 블러에서 나타나기, 그려진 밑줄, 카드 캐스케이드, 스크롤 시 텍스트. 사이트의 첫 화면 및 섹션에 대해 읽으세요.references/patterns.md— 기술 카탈로그: 마이크로 인터랙션, 진입, 숫자 변경, 스크롤, 페이지 전환, 텍스트; 각각이 효과적인 때와 해로운 때; 스타일별 모션 특성.references/tools.md— 코드 예제 및 선택 규칙이 포함된 CSS에서 GSAP까지의 도구 사다리.