모션

모션 (Motion) — 개발 가이드

PatternFly 컴포넌트에서 옵트인 애니메이션을 활성화하고, 전역으로 애니메이션을 제어하며, 커스텀 모션과 모션 토큰을 사용하는 방법까지 개발 관점에서 설명해 드릴게요.

출처: 문서

본문

옵트인 애니메이션 활성화하기 (Enabling opt-in animations)

우리는 컴포넌트에서 애니메이션을 기본으로 지원하려고 노력해요. 하지만 breaking change를 피하기 위해 일부 애니메이션은 수동으로 옵트인해야 해요. 옵트인 애니메이션은 코드베이스에 추가 업데이트가 필요하며, 테스트 설정에 따라 적절히 구성하지 않으면 테스트 실패를 일으킬 수도 있어요.

다음 컴포넌트에는 옵트인 애니메이션이 있으며, 올바른 구현을 위한 예제 링크가 있어요:

  • 알림 (알림 그룹 내) (Alert within alert groups)
  • 듀얼 리스트 셀렉터 (트리 포함) (Dual list selector with tree)
  • 폼 필드 그룹 (Form field groups)
  • 네비게이션 (확장 가능) (Navigation, expandable)
  • 알림 배지 (Notification badge)
  • 검색 입력 (확장 가능) (Search input, expandable)
  • 테이블 (확장 가능, 베타) (Table, expandable, in beta)
  • 테이블 (복합 확장, 베타) (Table, compound expandable, in beta)
  • 탭 (HTML 전용 구현) (Tabs, HTML-only implementations)
  • 트리 뷰 (모든 예제) (Tree view, all examples)

참고: 일부 엣지 케이스에서는 리소스 집약적인 페이지가 브라우저 메모리 문제를 일으켜 애니메이션이 제대로 실행되지 않을 수 있어요. 예를 들어 애니메이션 스피너는 특히 메모리 집약적이라, 스피너가 여러 개 있는 페이지는 메모리를 너무 많이 소비해 모든 애니메이션이 비활성화될 수 있어요.

애니메이션 일괄 활성화 (Bulk-enabling animations)

우리는 옵트인이 필요한 컴포넌트에 hasAnimations prop을 자동으로 추가해 주는 enable-animations codemod를 제공해요.

코드베이스에 따라 이 codemod가 추가 주의가 필요한 breaking change를 도입할 수 있음을 알아두세요. codemod를 실행하면 @patternfly/react-core 패키지만 애니메이션에 옵트인할지, 아니면 @patternfly/react-table까지 포함할지 묻는 질문을 받게 돼요.

옵트인 애니메이션을 활성화하려면 다음 명령을 실행하세요:

npx @patternfly/pf-codemods --only enable-animations /path-to-src

전역 애니메이션 제어 (Global animation control)

AnimationsProvider는 애플리케이션에서 애니메이션 동작을 전역으로 제어할 수 있는 React context provider예요. 이를 사용하면 코드베이스의 모든 PatternFly 컴포넌트에서 애니메이션을 중앙에서 관리할 수 있어, 축소 모션을 선호하는 사용자에게 비활성화하거나 성능을 최적화하기 쉽게 해줘요.

권장 설정과 사용법 (Recommended setup and usage)

모든 PatternFly 컴포넌트에 전역 애니메이션 구성을 제공하려면 애플리케이션의 루트에 AnimationsProvider를 배치하고, hasAnimations: true 또는 hasAnimations: false를 전달하세요:

// App.tsx or index.tsx
import React from 'react';
import { AnimationsProvider } from '@patternfly/react-core';
import { MyApplication } from './MyApplication';

const App: React.FunctionComponent = () => {
  return (
    <AnimationsProvider hasAnimations={true}>
      <MyApplication />
    </AnimationsProvider>
  );
};

export default App;
컴포넌트 오버라이드 (Component overrides)

AnimationsProvider를 사용할 때도 컴포넌트에 hasAnimations를 직접 전달해 전역 설정인 true/false를 덮어쓸 수 있어요. 예를 들어 <AlertGroup isToast hasAnimations={false}>는 전역 설정인 true를 덮어써요.

또한 컴포넌트를 AnimationsProvider로 감싸서 그곳에서 애니메이션을 제어할 수도 있어요:

<AnimationsProvider hasAnimations={false}>
  {criticalAlerts.map(alert => (
    <Alert key={alert.id} variant={alert.variant} isLiveRegion>
      {alert.message}
    </Alert>
  ))}
</AnimationsProvider>

참고: 위 코드 예시의 JSX는 본문에서 압축되어 일부 자식 요소가 표시되지 않았어요. 실제 구현은 @patternfly/react-core의 AnimationsProvider 문서를 참고하세요.

조건부 애니메이션 (Conditional animations)

사용자 선호나 시스템 설정에 따라 조건부로 애니메이션을 활성화할 수 있어요:

// App.tsx - Respect user's motion preferences
import React from 'react';
import { AnimationsProvider } from '@patternfly/react-core';
import { MyApplication } from './MyApplication';

const App: React.FunctionComponent = () => {
  // Respect user's reduced motion preference
  const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  return (
    <AnimationsProvider hasAnimations={!prefersReducedMotion}>
      <MyApplication />
    </AnimationsProvider>
  );
};

export default App;

커스텀 모션 (Custom motion)

새 PatternFly 확장을 만드는 것 같은 일부 시나리오에서는 커스텀 모션 동작을 구현해야 할 수도 있어요. 새 애니메이션을 만들 때 다음을 확인하세요:

  • 그 애니메이션에 대한 기존 지원이 없는지.
  • 애니메이션이 우리의 모션 원칙을 준수하고 prefers-reduced-motion 설정을 존중하는지.
  • 구현이 다음 섹션에서 설명하는 적절한 의미 모션 토큰을 사용하는지.

모션 토큰 (Motion tokens)

PatternFly 컴포넌트 애니메이션은 지속 시간(duration), 지연(delay), 타이밍(timing)을 지정하는 디자인 토큰으로 만들어져요. 우리는 base 토큰 위에 구축된 의미 토큰을 사용해 모션을 구현해요. 의미 모션 토큰은 --pf-t--global--motion--로 시작해요.

커스텀 모션을 구현할 때는 토큰 시스템을 숙지하고 문서에 설명된 모션 토큰을 사용해야 해요.

지속 시간 (Duration)

지속 시간 토큰은 각 애니메이션이 완료되는 데 걸리는 시간을 지정해요. 우리는 각 애니메이션 유형에 따라 사전 정의된 지속 시간 토큰을 제공해요.

애니메이션 (Animation) 설명 (Description) 토큰 (Tokens)
슬라이드 아웃 (Slide-out) 요소를 뷰포트 밖으로 이동시킴 --pf-t--global--motion--duration--slide-out--short, --pf-t--global--motion--duration--slide-out--default, --pf-t--global--motion--duration--slide-out--long
슬라이드 인 (Slide-in) 오프스크린에서 요소를 뷰포트 안으로 이동시킴 --pf-t--global--motion--duration--slide-in--short, --pf-t--global--motion--duration--slide-in--default, --pf-t--global--motion--duration--slide-in--long
페이드 (Fade) 요소에 점진적 전환을 적용함 --pf-t--global--motion--duration--fade--short, --pf-t--global--motion--duration--fade--default, --pf-t--global--motion--duration--fade--long
아이콘 (Icon) 아이콘에 전환을 적용함 --pf-t--global--motion--duration--icon--short, --pf-t--global--motion--duration--icon--default, --pf-t--global--motion--duration--icon--long

지연 (Delay)

지연 토큰은 애니메이션이 시작되기 전에 경과해야 하는 시간을 지정하며, "none", "short", "default", "long"이 있어요.

토큰 (Token) 값 (Value)
--pf-t--global--motion--delay--none 0ms
--pf-t--global--motion--delay--short 50ms
--pf-t--global--motion--delay--default 100ms
--pf-t--global--motion--delay--long 7000ms

타이밍 (Timing)

타이밍 토큰은 애니메이션이 취하는 이징 경로를 지정하며, cubic Bezier 곡선으로 정의돼요. 이 곡선은 곡선의 시작과 끝 지점, 그리고 초기·최종 시간과 상태를 나타내요.

타이밍 함수 (Timing function) 설명 (Description) 토큰 (Token) 값 (Value)
가속 (Accelerate) 천천히 시작해 끝까지 점진적으로 가속함. "ease-in" 전환과 동일 --pf-t--global--motion-timing-function--accelerate cubic-bezier(.4, 0, .7, .2)
기본 (Default) 천천히 시작해 속도를 내고 끝에서 느려짐. "ease-in-out" 전환과 동일 --pf-t--global--motion-timing-function--default cubic-bezier(.4, 0, .2, 1)
감속 (Decelerate) 빠르게 시작해 끝까지 점진적으로 감속함. "ease-out" 전환과 동일 --pf-t--global--motion-timing-function--decelerate cubic-bezier(0, 0, .2, 1)

축소 모션 테스트하기 (Testing reduced motion)

축소 모션을 수동으로 테스트하는 방법은 2가지예요:

  • 브라우저에서: Chrome, Firefox, Safari
  • OS에서:
    • macOS: 시스템 설정 > 손쉬운 사용 > 디스플레이로 가서 "동작 줄이기(Reduce motion)"를 활성화하세요.
    • Windows 10: 설정 > 접근성 > 디스플레이로 가서 "Windows에서 애니메이션 표시(Show animations in Windows)"를 꺼세요.
    • Windows 11: 설정 > 접근성 > 시각 효과로 가서 "애니메이션 효과(Animation Effects)"를 끄세요.

더 알아보기 (Learn more)