07 — Motion Accessibility (멀미·전정장애·윤리)

한 줄 답: 모션은 모두에게 멋진 것이 아니다. 인구의 약 35%가 vestibular(전정) 민감성을 가지며, 이들에게 패럴랙스·자동 캐러셀·큰 슬라이드 전환은 두통·메스꺼움·균형 상실을 유발한다. @media (prefers-reduced-motion: reduce)디자인 선호가 아니라 WCAG 2.3 의무다.


Why — 왜 모션 챕터의 마지막에 이게 오는가

지금까지 챕터(01~06)는 어떻게 더 부드럽게 움직이게 할까를 다뤘다. 이 챕터는 어떻게 안 움직이게 할까를 다룬다.

이는 소수의 예외 처리가 아니다. WHO 추산 전 세계 vestibular dysfunction 유병률 ~35%. 그 외 ADHD·자폐 스펙트럼·편두통 환자·임산부도 모션에 강한 민감성을 가진다. 모션을 끌 수 없는 인터페이스는 그 자체로 결함이다.


How — 어떻게 적용하나

1) prefers-reduced-motion 미디어 쿼리

@media (prefers-reduced-motion: reduce) {
  /* 모션을 꺼야 할 때의 스타일 */
}

값 2가지:

  • no-preference (기본) — 사용자가 모션 감소를 선택하지 않음
  • reduce — 사용자가 OS·브라우저 설정에서 모션 감소를 선택

OS 설정 경로:

  • macOS — System Settings → Accessibility → Display → Reduce motion
  • iOS — Settings → Accessibility → Motion → Reduce Motion
  • Windows — Settings → Accessibility → Visual effects → Animation effects (off)
  • Android — Settings → Accessibility → Remove animations

2) 두 가지 전략 — 끄기 vs 대체

Tailwind/MUI 등 라이브러리는 보통 전략 A를 전역 default로 깔고, 필요한 곳만 전략 B로 정밀 대체.

3) 전역 기본 (안전 망)

거의 모든 디자인 시스템의 첫 줄:

@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;
  }
}

0.01ms인가? 0이면 애니메이션 자체가 발동 안 됨animationend 이벤트 미발생 → JS 콜백이 안 불림. 0.01ms실질적으로 즉시 끝나지만 이벤트는 발생. JS와 호환되는 안전한 값.

4) 정밀 대체 — 필수 의미 보존

전체를 끄면 어떤 변화가 일어났는지 사용자가 모를 수도 있다. 예: 모달이 열렸다는 신호조차 사라지면 안 됨.

.modal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 200ms, transform 200ms;
}
.modal.open {
  opacity: 1;
  transform: translateY(0);
}
 
@media (prefers-reduced-motion: reduce) {
  .modal {
    transform: none;  /* 위치 이동은 꺼라 */
    transition: opacity 100ms;  /* 페이드는 짧게 유지 */
  }
}

원칙: 위치·크기 변화는 끄되, 의미 전달용 페이드는 유지.

5) JS API — matchMedia

JS 측에서도 동일하게 감지 가능:

const reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
 
if (reduce.matches) {
  /* GSAP, Framer Motion, Lottie 등에 비활성 옵션 전달 */
  gsap.globalTimeline.timeScale(0);
}
 
/* 사용자가 설정을 바꿀 수도 */
reduce.addEventListener('change', () => { /* 재적용 */ });

6) View Transitions·Scroll-driven에도 적용

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
  * {
    animation-timeline: auto !important;
  }
}

자세한 건 05-view-transitions, 06-scroll-driven.


What — 안전한 모션 가이드라인

A. WCAG 2.3 Animation from Interactions

기준등급내용
2.3.1A1초에 3회 이상 깜빡임 금지 (광민감성 발작)
2.3.3AAA인터랙션으로 발생하는 모션은 비활성화 가능해야 함

미국 ADA 소송 사례: 2019년 Beyoncé.com이 자동재생 비디오와 패럴랙스로 시각·전정 장애인이 사용할 수 없다는 소송. 합의로 끝났고, 이후 프리미엄 브랜드 사이트는 reduced-motion 지원이 기본이 됨.

B. 위험 강도 매트릭스

C. 안전한 기본값

속성안전 범위비고
transform translate≤ 20px모달·toast 진입
transform scale0.95 ~ 1.05hover/press
transform rotate≤ 15deg토글 화살표
transition-duration150~300ms표준 UI
animation iteration1 또는 reduce 시 1무한 반복은 reduce 시 정지
패럴랙스 차이 속도reduce 시 0%끄기

D. 라이브러리별 통합

  • Framer Motion: MotionConfig reducedMotion="user" 또는 useReducedMotion() hook
  • GSAP: gsap.matchMedia() 안에 reduce 케이스 분기
  • Lottie: lottie-react에서 loop={false}, autoplay={false}로 fallback
  • Tailwind: motion-safe: / motion-reduce: variant
<div class="motion-safe:animate-bounce">팝</div>

motion-safe:animate-bouncereduced-motion이 아닌 사용자에게만 적용.


What-if — 잘못 만지면

1) prefers-reduced-motion을 전혀 처리 안 함

iOS Safari로 패럴랙스 사이트 방문 → 멀미 사용자가 5초 안에 페이지를 닫는다. 분석 도구에 이 사용자 세그먼트의 이탈률이 따로 잡히지 않으므로 디자이너는 자신의 사이트가 누구를 쫓아내는지 모른다. WCAG 2.3.3 AAA 위반.

2) animation: none !important모든 곳에 일괄

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }  /* ❌ 너무 거침 */
}

문제:

  • 로딩 스피너까지 멈춤 → 사용자가 시스템이 죽은 줄 안다.
  • JS animationend 콜백이 안 불려 모달이 안 열림.

해결: animation-duration: 0.01ms (위 § 3의 전역 기본).

3) “예외적으로 중요한” 애니메이션을 reduced에서도 살림

@media (prefers-reduced-motion: reduce) {
  .super-important-spinner {
    animation: spin 1s infinite;  /* ❌ 사용자 의사 무시 */
  }
}

사용자가 명시적으로 모션을 꺼달라고 말했는데 *디자이너가 “이건 중요해서 켜둠”*은 윤리적으로 잘못. 정적 표시(progress bar 등)로 기능을 보존하되 모션은 끄는 것이 원칙.

4) Reduced에서 정보가 사라짐

.toast { animation: slide-in 200ms; }
@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; opacity: 0; }  /* ❌ 안 보임 */
}

모션을 꺼도 결과 상태는 보여야 함. forwards나 직접 최종 상태 적용:

@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; opacity: 1; }
}

5) 자동 캐러셀 (autoplay)

자동으로 5초마다 회전하는 캐러셀은 멀미 + 인지부하. WCAG 2.2.2 (Pause, Stop, Hide)에 따라 5초 이상 자동 움직임은 일시정지 컨트롤 의무. reduced-motion일 땐 자동재생 자체를 꺼라.

const reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
if (!reduce.matches) carousel.startAutoplay();

6) 색 + 모션 둘 다에 의지한 의미 전달

.error { animation: shake 200ms; color: red; }

색맹 사용자는 색을 못 보고, 모션 비활성 사용자는 흔들림을 못 본다. 둘 다 비활성이면 에러임을 인지 못함. 텍스트·아이콘 등 제3의 채널 필수.


Insight — 한 단락 이야기

“멀미는 디자인의 정직한 피드백이다.”

1990년대 VR 연구자들은 시각과 전정기관의 불일치가 멀미를 유발한다는 걸 정량적으로 밝혔다 (Cybersickness). 우리 뇌는 눈으로 본 움직임내이의 균형 감각이 일치할 거라 기대한다. 화면이 갑자기 옆으로 슬라이드하면, 내 눈은 움직이는데 내 몸은 가만히 있다 → 뇌는 독에 중독됐다고 판단해 구토 반사를 일으킨다. 패럴랙스가 위험한 이유는 원근 차이내 몸이 움직이는 신호로 오해되기 때문이다. 2014년 iOS 7의 큰 시차 효과가 출시되자 수십만 명의 사용자가 메스꺼움을 호소했고, Apple은 6개월 만에 Reduce Motion 설정을 추가했다. 그로부터 prefers-reduced-motion이 W3C 표준이 됐다 (2017). 흥미로운 점은 *이 설정을 켠 사용자가 평균 35%*라는 것 — 즉 멋진 모션최대 3분의 1의 사용자를 쫓아낼 수 있는 무기다. 모션 디자인의 윤리는 결국 단순하다: 사용자가 끄겠다고 하면 끈다. 그게 전부다.


요약 + Mermaid

  • vestibular 민감성 유병률 ~35% — 모션은 소수의 예외가 아니라 큰 사용자 세그먼트의 문제.
  • @media (prefers-reduced-motion: reduce)WCAG 2.3.3 AAA 의무.
  • 전역 기본: 모든 animation·transition의 duration: 0.01ms안전 망.
  • 정밀 대체: 위치 이동은 끄되, 의미 전달 페이드는 짧게 유지.
  • 위험 매트릭스: 패럴랙스·자동 캐러셀·큰 슬라이드·3D 회전은 무조건 끄기.
  • View Transitions·Scroll-driven에도 동일하게 적용.
  • 라이브러리(Framer/GSAP/Lottie)는 모두 reduce 옵션 지원.
  • 자동재생 캐러셀은 WCAG 2.2.2 (Pause, Stop, Hide) 의무.
  • 모션 + 색만으로 의미 전달 금지 — 제3의 채널 (텍스트·아이콘) 필수.

이 챕터로 모션 도메인이 마무리된다. 다음 도메인: 07-responsive — 이 모션이 어떤 뷰포트·컨텍스트에서 동작하는가.