UX 모션
인터랙션을 설계하고 작성할 때 다음 규칙을 적용하세요. 먼저 프로젝트 모션 토큰을 검사하세요. 리포지토리의 AGENTS.md, CLAUDE.md, 토큰 파일, 디자인 문서가 아래 기본값보다 우선합니다.
항상 활성화되는 핵심
- 기본 결정: 기능 UI는 일반적으로 120~180ms 대역에서 동작합니다. 프로젝트 토큰이 우선합니다.
- 공간 연속성, 상태 변경, 입력 피드백 또는 갑작스러운 팝 방지를 위해 애니메이션을 사용하세요.
- 이름이 있는
transform및opacity전환을 선호하세요.transition: all은 절대 사용하지 마세요. - 진입 표면은 감속하고, 종료 표면은 가속해야 합니다. 종료는 더 짧을 수 있습니다.
- 확장 표면은
scale(0.96)부근에서 시작하고,scale(0)에서 시작하지 마세요. prefers-reduced-motion: reduce에서 모션을 대체 가능하게 유지하고, 이해도와 키보드 접근성을 보존하세요.- 드래그 시 포인터를 캡처하고, 보조 터치를 방어하며, 하드웨어에서 제스처를 테스트하세요.
- 모션을 작성하거나 일반적인 오버레이를 건드리기 전에 이 파일 전체를 읽으세요. 클립 패스, 3D, WAAPI 또는 성능 심층 분석에만
REFERENCE.md를 사용하세요.
1. 모션을 적용할지 결정하기
노출 빈도를 제약 조건으로 사용하세요. 반복적으로 자주 수행되는 작업은 즉각적이거나 거의 즉각적이어야 합니다. 드문 표면은 공간 연속성을 확립할 수 있습니다. 드물고 설명적인 순간은 더 많은 개성을 담을 수 있습니다. 모션은 변경 사항을 명확히 하고, 입력을 인정하며, 위치를 보존하거나, 갑작스러운 등장을 방지해야 합니다. 그 중 어떤 것도 수행하지 않는다면 제거하세요. 키보드 단축키가 장식용 모션을 기다리게 하지 마세요.
2. 지속 시간 선택하기
120180ms 대역은 기본 결정입니다. 이는 Material 3의 발행된 short3(150ms), short4(200ms) 및 표준 전환 범위(250400ms)보다 의도적으로 더 좁습니다. 느린 기능 UI에 대한 반대 의사를 표현한 것이며, 발행된 접근성 또는 플랫폼 요구 사항이 아닙니다.
| 표면 | 시작점 |
|---|---|
| 누름 피드백 | 100~140ms |
| 툴팁 또는 작은 팝오버 | 120~160ms |
| 메뉴 또는 드롭다운 | 140~180ms |
| 모달 | 180ms |
| 시트 | 180ms; 뷰포트 대부분을 이동할 때 최대 250ms |
종료 시에는 더 짧은 쪽을 사용하세요. 이는 기본값이며, 제품 토큰을 재정의하지 않습니다.
3. 이징 선택하기
진입 표면은 강조되다가 안정되는 방식(감속)으로 도착해야 하고, 종료는 신속하게(가속) 사라져야 합니다. Material 3은 이러한 방향을 명시적으로 이름을 붙입니다:
:root {
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
--ease-enter: cubic-bezier(0.05, 0.7, 0.1, 1); /* 강조-감속 */
--ease-exit: cubic-bezier(0.3, 0, 0.8, 0.15); /* 강조-가속 */
}
linear는 시간과 같은 진행에만 사용하세요. 의도적인 중간점을 통과하는 상태에는 ease-in-out 곡선을 사용하세요. 이름만으로 곡선을 선택하지 마세요. 플롯된 모양과 이동 방향을 검사하세요.
4. 렌더링 비용 낮게 유지하기
transform 및 opacity를 선호하세요. 이들은 컴포지터에서 처리할 수 있습니다. 속성 이름을 지정하고 레이아웃을 애니메이션에서 배제하세요. 레이아웃 변경이 핵심이고 비용이 수용되지 않는 한 top, left, width, height, margin, padding 애니메이션을 피하세요. 고유 높이의 경우, 래퍼가 grid-template-rows: 0fr에서 1fr로 전환할 수 있으며, min-height: 0 내부 래퍼가 overflow: hidden으로 잘립니다. 이는 여전히 레이아웃을 수행하므로 프로파일링하고, 컴포지터 전용 단축키로 취급하지 마세요. will-change는 늦게, 간략하게, 프로파일링이 도움이 된다는 것을 보여준 후에만 사용하세요. 레이어는 리소스를 소모합니다.
5. 상태를 올바르게 만들기
- 누를 수 있는 컨트롤에 시각적 피드백을 제공하세요. 기존 색상, 테두리 또는 그림자 상태를 사용하거나, 적합한 경우 작은
scale(0.98)을 사용하세요. 위치 변환을 덮어쓰지 마세요. - 시각적 포커스, 키보드 활성화 및 비활성화 동작을 유지하세요. 애니메이션이 포커스 배치, Escape 처리 또는 의미 상태 업데이트를 지연시키지 않아야 합니다.
- 팝오버, 메뉴 및 툴팁은
transform-origin을 통해 앵커에서 성장합니다. 중앙 정렬 모달은 중앙에서 성장합니다. 상태가 변경되는 동안 원점을 안정적으로 유지하세요. - 재트리거 가능한 상태에는 전환을 선호하세요. 자체 포함된 이벤트에는 키프레임을 사용하세요.
- 호버 전용 기능은
@media (hover: hover) and (pointer: fine)으로 게이트를 설정하세요. - 진입 요소의 경우, 지원되는 곳에서는
@starting-style을 사용하거나, 전환 전에 초기 스타일을 관찰 가능하게 만드는 마운트된 상태를 사용하세요.
6. 감소된 모션은 대체를 의미함
prefers-reduced-motion 설정은 모션을 제거, 감소 또는 대체하는 것을 다룹니다. 대규모 패닝 및 스케일링은 전정 기관 자극을 유발할 수 있습니다. 이동 및 스케일을 불투명도 및 색상 변경으로 대체하되, 여전히 상태를 설명할 수 있는 경우에만 사용하세요. 포커스, 로딩 및 가시성 변경을 이해할 수 있게 유지하세요. 사용자가 더 적은 모션을 요청했다고 해서 요소가 사라지게 하지 마세요. CSS뿐만 아니라 JavaScript 기반 애니메이션에서도 이 설정을 존중하고, 페이지가 열려 있는 동안 설정 변경도 처리하세요. 필수 상태 변경을 완료하기 위해 transitionend 이벤트에 의존하지 마세요. 전환이 비활성화되거나 취소될 수 있습니다. 모든 애니메이션을 전역적으로 강제로 짧은 지속 시간으로 만들지 말고, 영향을 받는 구성 요소에 재정의 범위를 지정하세요.
7. 제스처
드래그가 시작되면 setPointerCapture()를 호출하세요. 이후 포인터 이벤트는 해제될 때까지 캡처 요소를 계속 대상으로 합니다. 조정된 속도 또는 거리 규칙에 따라 해제하세요. 보편적인 플릭 상수는 없으므로 실제 기기에서 보정하세요. 하드 경계 대신 댐핑으로 이동을 제한하세요. 제스처가 포인터를 소유하면 추가 터치 포인트를 무시하세요. 사용자가 진행 중인 제스처를 취소할 수 있게 하세요. pointercancel 및 lostpointercapture를 처리하여 드래그 상태를 지우세요. 제스처 축에 대해 touch-action을 선택하되 페이지 스크롤을 불필요하게 차단하지 마세요. 버튼 또는 키보드 대안을 제공하세요.
8. 인터럽션 및 스프링 처리하기
빠른 열기/닫기/다시 열기는 최신 요청 상태에서 안정되어야 합니다. 처음부터 다시 재생하는 대신 현재 시각적 상태에서 대상을 다시 지정하세요. 교체 또는 마운트 해제 시 오래된 콜백, 리스너 및 애니메이션을 취소하세요. 오래된 종료가 새로 열린 표면을 제거하지 않아야 합니다. 구성 요소의 포커스 수명 주기에 따라 숨겨지거나 종료 중인 콘텐츠를 키보드 탐색에서 제외하세요.
직접 조작 또는 연속성에 이점이 있고 프로젝트 라이브러리를 존중하는 경우 스프링을 사용하세요. 스프링 매개변수는 엔진마다 다르므로 강성 및 감쇠 값을 맹목적으로 복사하지 마세요. 실제 구성 요소에서 정착 시간 및 오버슈트를 조정하세요. 텍스트가 많은 표면에서는 바운스를 피하고, 감소 모션에서는 이동을 비활성화하세요.
9. 완료라고 판단하기 전에 확인하기
4배 느린 속도로 재생하여 속성이 함께 끝나고 올바른 위치에서 시작하는지 확인하세요. 빠르게 토글하여 스냅핑을 노출하세요. DevTools에서 감소 모션을 에뮬레이션하세요. 드래그를 경계 너머로 수행하고, 취소하고, 두 번째 터치를 추가하고, 실제 기기에서 테스트하세요. 런타임에 계산된 애니메이션 값은 REFERENCE.md를 참조하세요. 실제로 수행된 검사와 브라우저 또는 실제 기기가 필요한 검사를 명시하세요. 코드 검토만으로는 인지된 부드러움을 확립할 수 없습니다.
출력 검토
코드를 감사할 때, 가장 심각한 순서대로 하나의 간결한 표로 보고하세요:
| 파일:줄 | 현재 | 변경 대상 | 이유 |
|---|---|---|---|
Menu.tsx:18 | transition: all 300ms | 명명된 속성 및 프로젝트 토큰 | 우발적인 레이아웃 애니메이션 방지 |
코드에서 보이는 결과만 보고하세요. 차이가 깔끔하다면, 결과를 만들어내지 말고 그렇게 말하세요.
mad7droid가 선별했습니다.