움직임 줄이기는 사용자가 운영체제 설정에서 화면의 움직임을 줄여 달라고 고른 것입니다. 페이지는 미디어 쿼리 조건 prefers-reduced-motion으로 이 설정을 읽고, 조건 블록 안에서 전환과 transform을 꺼 카드가 떠오르지 않게 합니다.
화면 속 움직임에 어지럼을 느끼거나, 작은 움직임이 거듭되면 글에 집중하기 어려운 사람이 있습니다. 그런 사람은 운영체제에서 움직임 줄이기를 켜 두고 모든 사이트를 봅니다. 앞 레슨에서 만든 떠오르는 카드는 그 설정을 모르면 그대로 움직입니다. 15단원에서 화면 폭을 읽던 @media로 사용자 설정도 읽습니다. 이 레슨은 무엇을 꺼야 카드가 정말 원래 자리에 머무는지를 봅니다. 아래 실험대도 움직임 줄이기를 켠 기기에서는 단계별 정지 화면으로 보입니다.
그림 준비 중
1사용자 설정도 미디어 쿼리 조건이다
조건 블록의 꼴은 화면 폭 조건과 같습니다. 조건이 길어 괄호 안에서 줄을 나눕니다.
| 값 | 뜻 |
|---|---|
reduce | 움직임을 줄여 달라는 설정이 켜져 있다 — 조건이 맞는다 |
no-preference | 따로 고른 것이 없다 — reduce 조건은 맞지 않는다 |
설정을 켜지 않은 브라우저에서는 카드에 전환이 그대로 걸려 있습니다.
<div class="card">김치볶음밥</div>
.card {
transition:
transform 180ms ease;
}.card의transition-duration0.18s
그 뒤에 움직임 줄이기 조건 블록을 둡니다. 아래 잰 값은 움직임 줄이기를 켠 브라우저에서 잰 값입니다 — 결과 화면은 지금 이 기기의 설정대로 그려집니다.
@media (
prefers-reduced-motion: reduce
) {
.card {
transition: none;
}
}.card의transition-duration0s
조건이 맞을 때만 블록 안의 규칙이 카드에 닿습니다(브라우저 규칙 4). 괄호 안에서 : reduce를 빼고 prefers-reduced-motion만 적어도 같은 뜻입니다.
2전환과 transform을 둘 다 끈다
전환만 끄면 카드는 움직이지 않을 것 같지만, 아닙니다. transition: none은 두 상태 사이를 잇는 과정만 없앱니다. 마우스를 올리면 :hover의 transform은 여전히 닿아, 카드가 한순간에 4px 위로 옮겨 그려집니다.
<div class="card">김치볶음밥</div>
.card {
transition:
transform 180ms ease;
}
.card:hover {
transform: translateY(-4px);
}@media (
prefers-reduced-motion: reduce
) {
.card {
transition: none;
}
}.card의transition-duration0s.card의 위 자리4px
카드의 원래 위 자리는 body의 바깥 여백 8px입니다. 전환만 끈 카드는 4px에 떠 있습니다 — 순간 이동도 움직임입니다. 떠오르는 일을 없애려면 조건 블록에서 :hover의 transform도 none으로 바꿉니다.
| 조건 블록에서 끈 것 | 마우스를 올렸을 때 |
|---|---|
전환만(transition: none) | 한순간에 4px 위로 옮겨 그려진다 |
전환과 변형(transform: none도) | 원래 자리에 그대로 있다 |
3설정은 운영체제에, 흉내는 개발자 도구에
움직임 줄이기는 운영체제의 접근성 설정입니다. macOS는 시스템 설정의 손쉬운 사용에서 '동작 줄이기'를 켜고, Windows 11은 설정 → 접근성 → 시각 효과에서 '애니메이션 효과'를 끕니다. 휴대전화도 접근성 설정에 있습니다. 메뉴 자리와 이름은 판마다 달라, 설정 위쪽 검색 칸에 '동작'이나 '애니메이션'을 쳐서 찾습니다.
운영체제 설정을 바꾸면 다른 프로그램의 움직임도 함께 줄어듭니다. 페이지만 견줄 때는 개발자 도구로 설정을 흉내 냅니다(크롬 기준). 개발자 도구의 ⋮ 메뉴 → More tools → Rendering에서 Emulate CSS media feature prefers-reduced-motion 목록을 prefers-reduced-motion: reduce로 고릅니다. 흉내는 파일을 바꾸지 않습니다. 확인이 끝나면 No emulation으로 되돌려야 운영체제 설정을 다시 따릅니다.
예제
움직임 줄이기에서 떠오르지 않는 레시피 카드
앞 레슨의 떠오르는 카드에 조건 블록을 더합니다. 기본 전환과 :hover 규칙 뒤에 둡니다. 아래 잰 값은 움직임 줄이기를 켜고 첫 카드에 마우스를 올린 뒤의 값입니다.
<div class="recipe-card">
김치볶음밥
</div>
<div class="recipe-card">
계란말이
</div>
.recipe-card {
box-sizing: border-box;
width: 240px;
height: 100px;
margin-bottom: 16px;
border: 1px solid #d2d2d7;
transition:
transform 180ms ease;
}
.recipe-card:hover {
transform: translateY(-4px);
}@media (
prefers-reduced-motion: reduce
) {
.recipe-card {
transition: none;
}
.recipe-card:hover {
transform: none;
}
}.recipe-card의transition-duration0s.recipe-card의transformnone.recipe-card의 위 자리8px.recipe-card + .recipe-card의 위 자리124px
첫 카드는 원래 자리 8px에 머뭅니다. 둘째 카드의 124px은 움직임을 켰을 때와 같습니다 — transform은 처음부터 배치를 바꾸지 않아, 끄더라도 이웃의 자리는 그대로입니다(브라우저 규칙 8). 카드의 글과 링크 같은 내용과 기능은 두 설정에서 똑같이 남습니다.
자주 틀리는 곳
틀린 생각: 움직임 줄이기면 움직이는 것과 함께 있던 꾸밈 · 내용도 끈다.
<p>김치볶음밥</p>
<a href="kimchi.html">자세히</a>
@media (
prefers-reduced-motion: reduce
) {
a {
display: none;
}
}a의 접근성 나무빠짐
움직임 줄이기를 켠 사람에게는 '자세히' 링크가 화면에서도, 화면 읽기 프로그램에서도 사라졌습니다. 설정은 움직임을 줄여 달라는 요청이지 내용을 줄여 달라는 요청이 아닙니다.
맞는 규칙: 끄는 것은 자리 · 크기를 바꾸는 움직임(transition · transform)뿐입니다. 색이 이어 바뀌는 전환처럼 자리를 옮기지 않는 것은 남겨도 되고, 내용과 기능은 그대로 둡니다.
틀린 생각: 내 컴퓨터에서 카드가 안 떠오르니 transform 코드가 틀렸다.
<div class="card">김치볶음밥</div>
.card {
transition:
transform 180ms ease;
}
.card:hover {
transform: translateY(-4px);
}@media (
prefers-reduced-motion: reduce
) {
.card:hover {
transform: none;
}
}.card의transformnone
코드는 맞습니다. 운영체제의 움직임 줄이기가 켜져 있거나 개발자 도구의 흉내가 남아 있으면 조건 블록이 맞아 카드가 머뭅니다. Computed 창에서 마우스를 올린 카드의 transform이 none이면 조건 블록이 이긴 것입니다.
맞는 규칙: 움직임이 안 보이면 코드를 고치기 전에 설정과 흉내를 먼저 봅니다. 3절의 Rendering 흉내를 No emulation으로 두고, 운영체제 설정도 확인합니다.
틀린 생각: 조건 블록은 어디에 두어도 조건이 맞으면 이긴다.
<div class="card">김치볶음밥</div>
@media (
prefers-reduced-motion: reduce
) {
.card:hover {
transform: none;
}
}
.card:hover {
transform: translateY(-4px);
}.card의 위 자리4px
조건이 맞았는데도 카드가 떠 있습니다. 조건 블록은 명시도를 올리지 않습니다. 두 규칙의 선택자가 같아 명시도가 같으니 나중에 쓴 아래 규칙이 이겼습니다(브라우저 규칙 5).
맞는 규칙: 조건 블록은 그것이 이겨야 할 기본 규칙 뒤에 둡니다. 15단원 모바일 먼저와 미디어 쿼리의 조건 블록 차례와 같습니다.
확인 문제
1. 예제의 조건 블록에서 .recipe-card:hover의 transform: none;을 transform: translateY(-2px);로 바꿉니다. 움직임 줄이기를 켜고 첫 카드에 마우스를 올리면 카드의 위 자리는 몇 px일까요?
- ① 8px
- ② 6px
- ③ 4px
힌트
마우스를 올린 카드에 닿는 transform 선언이 둘입니다. 조건이 맞을 때 어느 쪽이 나중에 쓰였는지 보세요.
정답
②입니다.
<div class="card">카드</div>
.card:hover {
transform:
translateY(-4px);
}
@media (
prefers-reduced-motion
) {
.card:hover {
transform:
translateY(-2px);
}
}.card의 위 자리6px
- 조건 블록의
translateY(-2px)이 뒤에 있어 이깁니다. 전환은 꺼져 있으니 카드는 한순간에 원래 자리 8px보다 2px 위인 6px에 그려집니다. - ①은 조건 블록이 늘 움직임을 없앤다고 본 것입니다. 블록 안에 적은 값이 그대로 쓰입니다. 접기 안 코드는 줄 폭 때문에
reduce를 뺀 꼴로 적었습니다 — 1절대로 같은 뜻입니다.
2. 움직임 줄이기 설정에서 카드가 마우스를 올려도 원래 자리에 있게 하려 합니다. ____ 자리를 채우세요.
@media (
prefers-reduced-motion: reduce
) {
.card {
transition: none;
}
.card:hover {
transform: ____;
}
}
힌트
2절 표의 아래 줄을 보세요.
정답
none입니다.
<div class="card">카드</div>
.card:hover {
transform:
translateY(-4px);
}
@media (
prefers-reduced-motion
) {
.card:hover {
transform: none;
}
}.card의 위 자리8px
translateY(0)도 원래 자리에 그립니다. none은 변형을 아예 없앤다는 뜻이라 읽기에 더 분명합니다.
3. 여행 일정 페이지의 날짜 칸입니다. 움직임 줄이기를 켠 사람이 칸에 마우스를 올리면 칸은 어떻게 될까요?
<div class="day">첫째 날</div>
.day {
width: 200px;
transition: transform 300ms;
}
.day:hover {
transform: scale(1.05);
}같은 코드에 조건 블록을 이어 붙입니다.
@media (
prefers-reduced-motion: reduce
) {
.day {
transition: none;
}
}
- ① 커지지 않는다
- ② 한순간에 1.05배로 커진다
- ③ 0.3초 동안 1.05배로 커진다
힌트
조건 블록이 바꾸는 선언과 바꾸지 않는 선언을 나눠 보세요.
힌트 둘
transition: none이 없애는 것이 과정인지 끝 모양인지 2절에서 찾아보세요.
정답
②입니다.
<div class="day">첫째 날</div>
.day {
width: 200px;
transition:
transform 300ms;
}
.day:hover {
transform: scale(1.05);
}@media (
prefers-reduced-motion
) {
.day {
transition: none;
}
}.day의transition-duration0s.day의 너비210px
- 조건 블록이 전환만 꺼, 과정 없이 끝 모양인 1.05배(200 × 1.05 = 210)로 그려집니다.
- ①은
transition: none이 움직임을 다 끈다고 본 것입니다. 커지지 않게 하려면.day:hover에transform: none도 둡니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
예제의 HTML과 두 CSS를 index.html과 style.css로 저장하고 link로 이어 엽니다(문서 뼈대의 body 안에 예제 HTML을 넣습니다). 3절대로 개발자 도구에서 움직임 줄이기를 흉내 내고, 조건 블록의 .recipe-card:hover 규칙을 지운 뒤 저장하고 새로고침합니다. 첫 카드에 마우스를 올려 카드가 순간 떠오르는지 보고, 끝나면 흉내를 No emulation으로 되돌립니다.