동작 줄이기 설정 존중하기 (matchMedia)

튜토리얼 — 동작 줄이기 설정 존중하기 (matchMedia)
DarkModeBadge는 다크 모드 여부를 글자로 보여 주기만 했습니다. 이번엔 matchMedia로 알아낸 조건에 따라 실제로 다른 화면을 그립니다 — 8.1절 개념에서 말한 "다른 컴포넌트를 보여 준다"가 이거예요.
검사할 조건은 prefers-reduced-motion 입니다. 어지럼증 등으로 화면 움직임이 불편한 사용자는 운영체제에서 "동작 줄이기"를 켭니다. 우리는 그 설정을 감지해, 애니메이션 대신 정지 화면을 보여 줍니다.
개념
matchMedia는 다크 모드든 화면 크기든 동작 줄이기든 쓰는 방법이 똑같습니다. 미디어 쿼리 문자열만 갈아 끼우면 됩니다.
window.matchMedia("(prefers-color-scheme: dark)"); // 다크 모드 (배운 것) window.matchMedia("(prefers-reduced-motion: reduce)"); // 동작 줄이기 (이번 것)
(prefers-reduced-motion: reduce)는 "사용자가 동작 줄이기를 켰는가"를 묻습니다. .matches가 true면 켜진 것입니다. 운영체제 설정 위치는 이렇습니다.
- macOS: 시스템 설정 → 손쉬운 사용 → 디스플레이 → 동작 줄이기
- Windows: 설정 → 접근성 → 시각 효과 → 애니메이션 효과
DarkModeBadge와 비교하면, matchMedia를 쓰고 정리 함수로 구독을 해제하는 뼈대는 완전히 같습니다. 한 번 익히면 미디어 쿼리만 바꿔 재사용하는 것 — 그걸 이 튜토리얼로 확인합니다.
함께 해보기
1단계 — MotionCard 컴포넌트 만들기
components/MotionCard.tsx 파일을 만듭니다.
"use client"; import { useState, useEffect } from "react"; export default function MotionCard() { const [reduceMotion, setReduceMotion] = useState(false); // 안전한 기본값 useEffect(() => { const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); const update = () => setReduceMotion(mq.matches); update(); // 처음 한 번 검사 mq.addEventListener("change", update); // 설정이 바뀌면 알림 return () => { mq.removeEventListener("change", update); // 정리: 구독 해제 }; }, []); return ( <div className="p-4 space-y-2"> {reduceMotion ? ( // 동작 줄이기 ON → 움직이지 않는 정지 화면 <p className="text-2xl">🔵 정지 — 동작 줄이기 설정을 존중합니다</p> ) : ( // 동작 줄이기 OFF → 통통 튀는 애니메이션 <p className="animate-bounce text-2xl">🔵 통통 튀는 중!</p> )} <p className="text-sm text-gray-500"> prefers-reduced-motion:{" "} {reduceMotion ? "reduce (켜짐)" : "no-preference (꺼짐)"} </p> </div> ); }
DarkModeBadge와 같은 점:
useState(false)로 안전한 기본값에서 시작 — 서버에는window가 없으니까요.matchMedia·addEventListener("change")·정리 함수의removeEventListener— 뼈대가 똑같습니다.
DarkModeBadge와 다른 점:
- 미디어 쿼리가
(prefers-reduced-motion: reduce)로 바뀌었습니다. - 결과를 글자로만 보여 주지 않고, JSX 분기(
reduceMotion ? 정지 : 애니메이션)로 다른 화면을 그립니다.animate-bounce는 통통 튀는 Tailwind 애니메이션입니다.
2단계 — 페이지에 올리고 확인
app/motion/page.tsx 파일을 만듭니다.
import MotionCard from "@/components/MotionCard"; export default function MotionPage() { return ( <main style={{ padding: 24 }}> <h2>동작 줄이기 설정 존중하기</h2> <MotionCard /> </main> ); }
/motion을 엽니다.
- 기본 상태(동작 줄이기 꺼짐)에서는 🔵 이모지가 통통 튑니다. ✅
- 운영체제에서 "동작 줄이기"를 켜면 → 새로고침 없이도 화면이 정지 상태로 바뀝니다. ✅
운영체제 설정을 바꾸기 번거롭다면, 크롬 개발자도구로도 됩니다.
F12 → 명령 메뉴(⌘⇧P) → "Show Rendering" → Emulate CSS prefers-reduced-motion 을
reduce로 바꿔 보세요. 배지와 애니메이션이 즉시 따라 바뀝니다.
확인 ✅ — matchMedia로 알아낸 조건(reduceMotion)에 따라 통통 튀는 화면과 정지 화면이 갈립니다. 운영체제 설정을 바꾸면 change 이벤트가 update를 불러, 새로고침 없이 화면이 따라 바뀝니다.
정리
matchMedia는 미디어 쿼리만 갈아 끼우면 다크 모드·화면 크기·동작 줄이기에 똑같이 쓰입니다.(prefers-reduced-motion: reduce)로 사용자의 동작 줄이기 설정을 감지할 수 있습니다..matches값에 따라 JSX를 분기하면, 글자만이 아니라 다른 화면 자체를 보여 줄 수 있습니다.useEffect안에서 쓰고, 정리 함수에서removeEventListener로 구독을 해제합니다.
연습 거리
DarkModeBadge와MotionCard의 공통 로직을useMediaQuery(쿼리문자열)라는 커스텀 훅으로 묶어, 두 컴포넌트가 함께 쓰게 만들기(orientation: portrait)로 세로/가로 화면을 감지해 표시하기- 동작 줄이기가 켜졌을 때는
animate-bounce대신animate-pulse(은은한 깜빡임)처럼 더 약한 효과를 주기

댓글
댓글을 작성하려면 이 필요합니다.