Chapter 10

모션

휴대폰에서 앱 아이콘을 누르면 앱 화면이 아이콘 자리에서 커지며 열린다. 닫으면 다시 그 아이콘 속으로 줄어든다. 아무도 설명하지 않았지만 우리는 그 앱이 "어디에서 와서 어디로 갔는지" 안다. 화면의 움직임은 잘 쓰면 말 없는 설명이 되고, 잘못 쓰면 기다림이 되거나 멀미가 된다. 이 장은 움직임의 빠르기 모양(이징), 길이(지속 시간), 출발점(공간 관계)을 직접 끌어 보며 배우고, 움직임을 줄여 달라는 사람의 설정을 존중하는 법을 다룬다.

움직임은 설명이다

화면의 요소가 위치, 크기, 투명도, 색을 시간에 따라 바꾸는 것을 통틀어 모션(Motion)이라고 한다. 웹에서는 한 상태에서 다른 상태로 넘어가는 동안의 움직임을 전환(Transition), 처음부터 정해 둔 여러 단계를 따라 움직이는 것을 애니메이션(Animation)이라고 부르며 CSS에도 두 가지가 따로 있다. 이 장에서는 둘을 함께 "움직임"이라고 부른다.

정지 화면에서는 두 상태 사이에 무슨 일이 있었는지 보이지 않는다. 메뉴가 닫혀 있다가 다음 순간 열려 있으면, 사람은 "무엇이 바뀌었는지"를 두 화면을 비교해 찾아야 한다. 움직임은 그 사이를 이어 준다. 화면의 움직임이 하는 일은 크게 네 가지다.

하는 일예없으면
상태 변화 알림눌린 버튼이 살짝 들어감, 체크 상자가 채워짐, 장바구니 숫자가 바뀜눌렸는지 몰라 한 번 더 누른다
공간 관계메뉴가 누른 버튼에서 펼쳐짐, 카드가 커져 상세 화면이 됨새 화면이 어디서 왔고 어떻게 돌아가는지 모른다
주의 끌기새로 온 알림이 한 번 흔들림, 오류 칸이 짧게 떨림변화가 화면 구석에서 조용히 일어나 놓친다
연속성목록이 정렬될 때 항목이 새 자리로 미끄러짐순서가 바뀐 줄 모르고 엉뚱한 것을 누른다

이 넷 중 어디에도 들지 않는 움직임, 예를 들어 화면이 열릴 때마다 모든 글자가 날아 들어오거나 스크롤할 때마다 사진이 빙글 도는 것은 장식이다. 장식이 늘 나쁜 것은 아니다. 그림책 같은 사이트, 한 번 보고 끝나는 행사 페이지라면 즐거움 자체가 목적일 수 있다. 하지만 사람이 매일 일을 보는 화면에서 장식은 기다림이 되고, 어떤 사람에게는 몸의 불편이 된다.

이 장의 시뮬레이터는 대부분 움직인다. 그래서 먼저 움직임을 줄이는 스위치를 둔다. 운영 체제에서 "동작 줄이기"(iOS·macOS), "애니메이션 삭제"(Android) 같은 설정을 켜 두었다면 브라우저가 그것을 알려 주고, 이 장의 시뮬레이터는 처음부터 움직임을 줄인다. 아래에서 직접 바꿀 수도 있다. 이 스위치는 장 전체에 적용된다.

SIMULATOR

이 장의 움직임 스위치

이 기기의 설정(실제 미디어 쿼리)—
이 장의 시뮬레이터—
완료 카드의 전환—
해볼 것: ① "이 기기의 설정"을 본다. 지금 쓰는 기기의 실제 값을 브라우저에서 읽어 온 것이다. ② "보통"을 고르고 "완료 카드 다시 보기"를 누른다. 9장의 모임 신청이 끝났을 때 나오는 카드가 아래에서 조금 올라오며 나타난다. ③ "움직임 줄임"을 고르고 다시 누른다. 카드가 제자리에서 짧게 나타난다. 움직임은 줄었지만 "무언가 새로 나타났다"는 정보는 남는다. ④ 운영 체제의 설정을 바꾸면 "기기 설정 따름"일 때 이 장이 바로 따라 바뀐다. (선택은 이 브라우저에만 저장된다. 이 장의 시뮬레이터는 움직임을 줄인 상태에서 저절로 움직이지 않고, 재생 단추를 눌렀을 때만 줄인 방식으로 보여 준다.)

이 스위치가 어떻게 기기의 설정을 읽는지는 이 장의 마지막 절에서 다룬다. 여기서 기억할 것은 하나다. 움직임을 줄인다는 것은 정보를 줄이는 것이 아니다. 카드가 나타났다는 사실, 메뉴가 열렸다는 사실은 그대로 전해야 한다. 바뀌는 것은 전하는 방법이다.

빠르기의 모양: 이징

현실의 물체는 정지 상태에서 갑자기 일정한 속도로 움직이지 않는다. 서랍을 열면 처음에 힘을 주어 빨라지고, 끝에 가서 천천히 멈춘다. 공을 던지면 손을 떠날 때 가장 빠르다. 같은 속도로 출발해 같은 속도로 멈추는 움직임은 기계처럼 보인다. 디즈니의 애니메이터 프랭크 토머스와 올리 존스턴은 『The Illusion of Life: Disney Animation』(1981)에서 애니메이션의 열두 원칙을 정리하며 그중 하나로 "천천히 출발하고 천천히 멈추기"(slow in and slow out)를 꼽았다. 움직임의 처음과 끝에 그림을 촘촘히 두고 가운데는 성기게 두는 방법이다.

화면에서 시간에 따라 진행이 빨라지고 느려지는 모양을 이징(Easing)이라고 한다. 시간의 몇 퍼센트가 지났을 때 움직임이 몇 퍼센트 진행했는지를 정하는 함수다. 시간과 진행이 같은 비율로 늘어나는 것은 선형(Linear), 처음이 느리고 끝이 빠른 것은 가속(ease-in), 처음이 빠르고 끝이 느린 것은 감속(ease-out), 양 끝이 느린 것은 가감속(ease-in-out)이다.

아래 시뮬레이터에는 네 개의 공이 같은 시간 동안 같은 거리를 간다. 시간 막대를 끌거나 "재생"을 눌러 비교한다. "같은 시간 간격의 자취"를 켜면 10분의 1 시간마다 공이 있던 자리가 점으로 남는다. 점이 촘촘한 곳은 느린 곳, 성긴 곳은 빠른 곳이다.

SIMULATOR

같은 시간, 다른 빠르기

지금 진행률—
처음 10% 시간에 간 거리—
마지막 10% 시간에 간 거리—
해볼 것: ① 시간 막대를 30%에 둔다. 감속(ease-out) 공은 벌써 절반쯤 갔고, 가속(ease-in) 공은 아직 출발선 근처다. ② 자취를 본다. 선형은 점 간격이 고르고, 감속은 처음이 성기고 끝이 촘촘하다. ③ "재생"을 누르고 공 네 개가 끝에 도착하는 모습을 비교한다. 가속 공은 끝에서 가장 빠른 채로 벽에 부딪치듯 멈춘다. 감속 공은 미끄러지듯 자리에 앉는다. (곡선은 CSS 표준 키워드 값이다: ease-in = cubic-bezier(0.42, 0, 1, 1), ease-out = cubic-bezier(0, 0, 0.58, 1), ease-in-out = cubic-bezier(0.42, 0, 0.58, 1). 차이가 잘 보이게 1초로 늘렸다. 움직임을 줄인 상태에서도 재생 단추는 누를 때만 움직인다.)

어느 곡선을 쓸지는 움직임의 방향이 정한다. 화면 안으로 들어오는 것(열리는 메뉴, 나타나는 알림)에는 감속이 어울린다. 빨리 출발해 사람의 눈앞에서 부드럽게 멈추므로 반응이 빠르게 느껴지고 도착한 자리가 분명하다. 화면 밖으로 나가는 것(닫히는 패널, 사라지는 알림)에는 가속이 어울린다. 천천히 출발해 빨라지며 떠나므로 끝을 기다릴 필요가 없다. 화면 안에서 자리를 옮기는 것(정렬되는 목록, 커지는 카드)에는 가감속이 자연스럽다. 시작과 끝이 모두 보이기 때문이다. 선형은 색이 바뀌거나 투명도가 바뀌는 것처럼 "위치"가 없는 변화, 또는 끝없이 도는 로딩 표시에 쓴다.

linear 0, 0, 1, 1 ease .25, .1, .25, 1 ease-in .42, 0, 1, 1 ease-out 0, 0, .58, 1 ease-in-out .42, 0, .58, 1 상자마다 가로는 시간(0 → 1), 세로는 진행률(0 → 1). 기울기가 가파른 곳이 빠른 곳이다.
그림 1. CSS 이징 키워드의 곡선. CSS의 transition-timing-function에 쓰는 다섯 키워드는 모두 cubic-bezier()의 특정 값이다(W3C, CSS Easing Functions Level 1). 아무것도 적지 않으면 ease가 쓰인다. ease는 ease-out과 비슷하게 끝이 부드럽지만 처음도 아주 조금 느리다.
포스트잇 플립북 손바닥만 한 포스트잇 스무 장을 겹쳐 두고, 각 장의 같은 높이에 왼쪽에서 오른쪽으로 굴러가는 공을 하나씩 그린다. 첫 묶음 열 장은 공의 간격을 자로 재어 모두 같게(선형) 그리고, 다음 열 장은 처음 간격을 넓게 그리다 끝으로 갈수록 좁게(감속) 그린다. 두 묶음을 엄지로 튕겨 넘기며 비교한다. 같은 거리, 같은 장수인데 감속 묶음의 공은 "멈춘다", 선형 묶음의 공은 "끊긴다". 이 장의 시뮬레이터가 보여 주는 자취 점이 바로 그 간격이다. 공 대신 서랍이나 문이 열리는 그림으로도 해 본다.

곡선을 직접 만지기: cubic-bezier

CSS의 이징 곡선은 3차 베지에 곡선(Cubic Bézier curve)으로 정한다. 글꼴의 윤곽선(TypeBook 11장)과 벡터 그림 도구의 펜 도구가 쓰는 바로 그 곡선이다. 네 점 \(P_0, P_1, P_2, P_3\)로 정하는데, 이징에서는 양 끝이 \(P_0 = (0, 0)\), \(P_3 = (1, 1)\)로 고정되고 가운데 두 조절점만 고른다.

$$B(s) = (1-s)^3 P_0 + 3(1-s)^2 s\, P_1 + 3(1-s)s^2 P_2 + s^3 P_3, \quad 0 \le s \le 1$$
\(B(s)\)의 가로 성분이 시간, 세로 성분이 진행률이다. \(s\)는 곡선 위를 지나가는 매개변수로, 시간 자체가 아니다. 그래서 브라우저는 주어진 시간 \(x\)에 대해 가로 성분이 \(x\)가 되는 \(s\)를 수치로 찾은 다음 세로 성분을 읽는다. CSS에서는 cubic-bezier(x1, y1, x2, y2)로 \(P_1 = (x_1, y_1)\), \(P_2 = (x_2, y_2)\)를 적는다. \(x_1, x_2\)는 0~1이어야 하고, \(y\)는 그 범위를 벗어나도 된다.

아래 그래프에서 두 조절점(손잡이)을 끌어 곡선을 만든다. 곡선 아래의 공은 그 곡선대로 움직인다. 조절점을 위로 1보다 높이 끌어 올리면 진행률이 100%를 넘었다가 돌아온다. 목표를 지나쳤다가 되돌아오는 이 움직임을 오버슈트(Overshoot)라고 한다.

SIMULATOR

cubic-bezier 편집기

조절점을 끈다
CSS 값—
시간 절반에 간 거리—
가장 멀리 간 곳—
해볼 것: ① "ease-out"에서 시작한다. 곡선이 처음에 가파르다. 공이 빨리 출발해 천천히 앉는다. ② 왼쪽 아래 구석의 조절점(P1)을 오른쪽으로 끌어 곡선을 S자로 만든다. "시간 절반에 간 거리"가 50%에 가까워진다. ③ "튀어 오름"을 누른다. 진행률이 100%를 넘었다 돌아와, 공이 목표를 지나쳤다 되돌아온다. 작은 단추나 아이콘에는 경쾌하지만 큰 패널에 쓰면 출렁거린다. ④ 한 번 움직이는 시간을 1500ms로 늘리면 곡선의 성격이 잘 보이고, 150ms로 줄이면 곡선끼리의 차이가 거의 느껴지지 않는다. (곡선의 계산은 CSS와 같은 방식이다: 주어진 시간에 대해 곡선의 가로 성분을 뉴턴법과 이분법으로 풀고 세로 성분을 읽는다. 움직임을 줄인 상태에서는 공이 멈추고 자취만 보인다.)

편집기에서 보듯 이징 곡선은 두 점으로 거의 모든 성격을 낼 수 있다. 그래서 디자인 체계마다 몇 개의 곡선만 골라 이름을 붙여 둔다. 곡선이 많으면 사이트 곳곳이 다른 리듬으로 움직여 어수선하다. 대부분의 사이트는 감속 하나(들어오는 것과 자리 옮기는 것), 필요하면 가속 하나(나가는 것) 정도면 충분하다. 오버슈트나 탄성처럼 성격이 강한 곡선은 아주 작은 요소에, 아주 가끔 쓴다.

베지에 곡선으로 안 되는 것 3차 베지에 곡선 하나로는 여러 번 튀는 공이나 용수철처럼 흔들리다 멈추는 움직임을 만들 수 없다. 이런 움직임은 물리 모형(질량, 용수철의 강도, 마찰)으로 계산해 여러 개의 키프레임으로 나누어 적는다. 최근 CSS에는 점 여러 개를 직선으로 이어 임의의 이징을 근사하는 linear() 함수가 생겨 이런 곡선을 CSS만으로 쓸 수 있게 되었고, 정해진 단계로 뚝뚝 끊어 움직이는 steps()도 있다. 다만 곡선이 복잡해질수록 "왜 이렇게 움직이는가"에 답하기 어려워진다는 것을 기억한다.

얼마나 길게: 지속 시간

같은 곡선이라도 시간이 다르면 전혀 다른 움직임이 된다. 너무 짧으면 움직임이 보이지 않아 순간 이동처럼 보이고, 너무 길면 사람이 화면을 기다리게 된다. 인터페이스의 반응 시간에 관한 고전적인 정리(로버트 밀러, "Response time in man-computer conversational transactions", 1968; 제이컵 닐슨, 『Usability Engineering』, 1993)는 대략 0.1초 안의 반응을 "즉각적"으로, 1초 안의 반응을 "생각의 흐름이 끊기지 않는" 정도로 본다. 화면 전환은 사람이 무언가를 누른 뒤에 일어나므로, 전환이 길어질수록 반응이 늦는 것처럼 느껴진다.

그래서 여러 디자인 지침이 인터페이스 전환에 대략 100~500ms 범위를 권하고, 작은 변화는 그 아래쪽, 큰 변화는 위쪽을 쓰라고 말한다. 정해진 표준이 아니라 실무에서 널리 공유된 경험칙(통설)이다. 기준은 세 가지다. 움직이는 거리와 크기(작은 체크 표시는 짧게, 화면 전체가 바뀌는 전환은 조금 길게), 방향(나가는 것은 들어오는 것보다 짧게), 그리고 얼마나 자주 보는가(하루에 백 번 여는 메뉴는 짧게, 한 번 보는 완료 화면은 조금 길게).

아래 휴대폰 목업에서 움직이는 대상의 크기와 지속 시간을 바꿔 가며 "열기·닫기"를 눌러 본다.

SIMULATOR

지속 시간과 거리

이동 거리(목업)—
평균 속도—
느낌(통설의 범위)—
이 크기에 흔히 쓰는 범위—
해볼 것: ① "더보기 패널", 250ms로 열고 닫는다. 패널이 내려오는 것이 보이지만 기다린다는 느낌은 없다. ② 지속 시간을 0으로 내린다. 패널이 순간 이동해, 무엇이 어디서 왔는지 놓치기 쉽다. ③ 1,000ms로 올린다. 움직임은 우아하지만 매번 1초씩 기다려야 한다. 하루에 몇 번 여는 메뉴라고 생각해 본다. ④ "작은 스위치"를 250ms로 두면 고작 20px을 가는 데 느릿하고, "화면 전체"를 150ms로 두면 큰 면이 휙 지나가 어지럽다. 같은 시간이라도 거리에 따라 속도가 달라진다. (느낌의 구간은 0.1초·1초의 고전적 기준과 실무 통설을 섞어 이 장이 정한 것이다: 100ms 미만 "순간", 100~200 "빠름", 200~400 "보통", 400~600 "느긋함", 600 초과 "기다림". 이징은 ease-out. 움직임을 줄인 상태에서는 이동 대신 짧은 페이드로 바뀐다.)

시뮬레이터에서 본 것처럼 지속 시간은 거리와 함께 생각해야 한다. 같은 250ms라도 20px을 가는 스위치는 느리고 300px을 가는 화면 전체는 빠르다. 그렇다고 속도를 일정하게 맞추면 큰 전환이 너무 길어지므로, 실무에서는 크기가 커질수록 시간을 조금씩만 늘린다. 또 하나, 사람의 눈은 들어오는 것을 보고 싶어 하지만 나가는 것은 보내 버리고 싶어 한다. 닫힘은 열림보다 짧게(예: 열림 250ms, 닫힘 150~200ms) 두는 경우가 많다.

느린 화면으로 본다 200ms짜리 움직임은 눈으로 보아서는 무엇이 잘못되었는지 알기 어렵다. 크롬 같은 브라우저의 개발자 도구에는 페이지의 애니메이션을 모아 보여 주고 재생 속도를 25%, 10%로 늦추는 패널이 있다. 느린 화면으로 보면 패널이 한 박자 늦게 출발하는지, 그림자가 따로 노는지, 끝에서 덜컥 멈추는지가 보인다. 거꾸로 디자인 시안을 만들 때는 "느린 화면에서 우아한" 움직임에 빠지기 쉽다. 시안은 반드시 원래 속도로, 실제 기기에서, 같은 동작을 열 번 반복해 보며 확인한다. 열 번째에도 기다려지지 않아야 한다.

전환이 알려 주는 공간

화면 전환의 가장 큰 쓸모는 공간 관계를 알려 주는 것이다. 웹 화면에는 실제 공간이 없지만, 사람은 움직임을 보고 머릿속에 공간을 짓는다. 메뉴가 "더보기" 단추에서 펼쳐지면 메뉴는 단추 안에 접혀 있던 것이 되고, 닫으면 단추 속으로 돌아간다. 카드를 눌렀을 때 그 카드가 커져 상세 화면이 되면, 상세 화면은 그 카드의 "안쪽"이 된다. 다음 화면이 오른쪽에서 밀려 들어오면 사람은 "한 칸 깊이 들어왔다"고 느끼고, 뒤로 가기를 누르면 왼쪽으로 돌아나갈 것을 기대한다.

단추에서 펼침 출발점 = 누른 곳 가운데서 확대 누른 곳과 상관없음 회전 옆에서 날아와 튕김 출발점이 엉뚱한 곳
그림 2. 메뉴가 나타나는 세 가지 방법. 셋 다 결과 화면은 같다. 다른 것은 움직임의 출발점이다. 출발점이 누른 단추와 같으면 메뉴는 "단추 안에 있던 것"이 되고, 닫을 때 돌아갈 곳도 분명하다. 출발점이 누른 곳과 상관없으면 움직임은 아무것도 설명하지 않는 장식이 된다.

아래 목업에서 "더보기" 메뉴와 신간 카드의 상세 화면을 네 가지 방식으로 열어 본다. 화면을 눌러도 열고 닫힌다. 점선 상자는 움직임이 시작한 자리다.

SIMULATOR

출발점이 있는 전환, 없는 전환

화면을 누르면 열고 닫힌다
출발점과 누른 곳의 거리—
전환 시간—
움직임이 알려 주는 것—
해볼 것: ① "더보기 메뉴", "누른 곳에서"로 열고 닫는다. 메뉴가 단추 아래에서 펼쳐지고 단추 속으로 접힌다. ② "가운데서 확대"로 바꾼다. 결과는 같은데 메뉴가 단추와 상관없는 곳에서 태어난다. ③ "날아와 튕김"으로 바꾼다. 이 장 끝의 케이스에서 지후가 처음 넣었던 움직임이다. 600ms 동안 화면 밖에서 회전하며 날아와 출렁인다. ④ "신간 카드 → 상세"로 바꿔 같은 비교를 한다. 카드에서 커진 상세 화면은 닫힐 때 그 카드로 돌아간다. ⑤ "움직임 없음"은 빠르지만, 무엇이 어디서 왔는지는 화면을 비교해 찾아야 한다. (전환 시간은 누른 곳에서·가운데서 250ms, 날아와 튕김 600ms. 거리는 목업 폭 300 기준의 화소다. 움직임을 줄인 상태에서는 모든 방식이 150ms 페이드로 바뀐다.)

"움직임 없음"이 늘 나쁜 것은 아니다. 바로 위에 단추가 있고 그 아래로 짧은 목록이 붙는 정도라면, 움직임 없이도 관계가 분명하다. 하지만 새 화면이 넓게 덮을수록, 원래 화면과의 관계가 덜 분명할수록 출발점을 지키는 전환이 도움이 된다. 반대로 출발점이 엉뚱한 움직임은 없느니만 못하다. 사람은 움직임에서도 의미를 읽으려 하기 때문에, 왼쪽에서 날아온 메뉴는 "왼쪽 어딘가에 있던 것"처럼 읽힌다.

움직임에도 명세를 쓴다 개발자에게 "부드럽게 열리게 해 주세요"라고 말하면 사람마다 다른 움직임이 나온다. 움직임도 간격이나 색처럼 값으로 넘긴다. 무엇이(메뉴 패널), 무엇에 반응해(더보기 단추를 누르면), 무엇을 바꾸며(위치와 크기, 투명도), 어디서 시작해(단추의 아래 오른쪽 모서리), 얼마 동안(250ms), 어떤 곡선으로(이징 토큰 이름), 닫힐 때는 어떻게(150ms, 같은 곡선, 단추로 돌아감). 이 일곱 칸을 표로 적어 두면 다른 화면을 만들 때도 같은 움직임을 쓸 수 있다. 6장에서 색과 글자를 토큰으로 만들었듯 시간과 곡선도 토큰으로 만든다.

차례로 나타나기

목록의 항목이 한꺼번에 나타나지 않고 조금씩 시간 차를 두고 하나씩 나타나게 하는 것을 스태거(Stagger, 차례 등장)라고 한다. 잘 쓰면 눈이 목록을 위에서 아래로 따라가게 이끈다. 문제는 시간이 더해진다는 것이다. 항목이 \(n\)개, 차례 간격이 \(d\), 한 항목의 전환 시간이 \(T\)이면 마지막 항목이 다 나타나는 시간은 \((n-1)\,d + T\)다. 항목이 많아지면 이 시간이 금세 1초를 넘는다.

SIMULATOR

차례 등장의 총 시간

마지막 항목이 다 보이는 시간—
첫 화면 카드 6개가 다 보이는 시간—
판정(이 장의 기준)—
해볼 것: ① 처음 값(카드 12장, 간격 120ms, 전환 400ms)으로 "다시 보기"를 누른다. 마지막 카드는 1.72초 뒤에야 다 나타난다. 아래 막대그래프는 카드마다 기다리는 시간(옅은 막대)과 나타나는 시간(진한 막대)이다. ② 항목 수를 24로 올린다. 3초 넘게 기다려야 마지막 카드를 누를 수 있다. ③ 간격을 30ms, 전환을 250ms로 줄인다. 차례 느낌은 남고 총 시간은 0.6초 아래로 줄어든다. ④ 간격을 0으로 하면 모두 한꺼번에 나타난다. (판정: 총 시간 500ms 이하 "짧음", 1,000ms 이하 "눈에 띔", 그보다 길면 "기다리게 함". 이 장이 정한 기준이다. 휴대폰 첫 화면에 카드 6개가 보인다고 가정했다. 움직임을 줄인 상태에서는 모든 카드가 차례 없이 한 번에 짧게 나타난다.)

차례 등장을 쓸 때는 총 시간에 상한을 둔다. 많이 쓰는 방법은 두 가지다. 간격을 아주 짧게(수십 ms) 두거나, 처음 몇 개(첫 화면에 보이는 것)에만 차례를 주고 나머지는 한꺼번에 보이게 한다. 그리고 차례 등장은 처음 한 번만 쓴다. 필터를 바꿀 때마다, 뒤로 가기로 돌아올 때마다 목록이 다시 하나씩 나타나면 사람은 매번 기다려야 한다.

과한 움직임과 전정 장애

귀 안쪽의 전정 기관(Vestibular system)은 몸의 기울기와 움직임을 느껴 균형을 잡는다. 이 기관이나 그 신호를 처리하는 뇌에 문제가 생긴 상태를 전정 장애(Vestibular disorder)라고 한다. 어지럼증, 메스꺼움, 두통 같은 증상이 나타나는데, 눈으로 보는 움직임과 몸이 느끼는 움직임이 어긋날 때 증상이 생기거나 심해지기도 한다. 멀미와 비슷한 원리다. 전정 장애가 없어도 편두통이 있거나, 피곤하거나, 나이가 들어 균형 감각이 약해진 사람은 화면의 큰 움직임에 불편을 느낄 수 있다.

모든 움직임이 문제인 것은 아니다. 문제가 되기 쉬운 것은 화면의 넓은 면적이 움직이는 것, 특히 사람이 일으키지 않은 움직임, 스크롤과 속도가 다르게 움직이는 배경(시차 스크롤), 화면 전체가 확대·축소되거나 회전하는 전환, 빠르게 오가는 움직임이다. 작은 단추의 눌림이나 투명도 변화는 대부분 괜찮다.

아래 목업은 지후가 만든 첫 화면이다. 서점 사진 위에 제목이 있고, 스크롤하면 사진이 글자보다 느리게 움직이며(시차) 조금씩 커진다. 화면을 위아래로 끌어 스크롤한다.

SIMULATOR

시차 스크롤과 확대

화면을 위아래로 끈다
글자와 배경의 속도 차이—
스크롤과 다르게 움직이는 면적—
사진 확대—
해볼 것: ① 화면을 천천히 위로 끌어 스크롤한다. 손가락은 글자를 끌고 있는데 사진은 뒤처져 따라온다. 화면 안에 속도가 다른 두 층이 생긴다. ② 확대를 켠 채 빠르게 오르내린다. 사진이 커졌다 작아졌다 하며 화면의 절반 가까이가 출렁인다. ③ 시차를 0으로 내리고 확대를 끈다. 사진도 글자와 함께 움직여, 손가락과 화면이 한 몸처럼 움직인다. ④ 이 장 맨 위의 스위치를 "움직임 줄임"으로 두면 시차와 확대가 저절로 꺼진다. (면적은 목업 화면에서 사진이 차지하는 비율로 셌다. 어지럼증을 일으키는 문턱값은 사람마다 달라서 이 장은 숫자로 판정하지 않는다.)

웹 접근성 지침에는 움직임에 관한 기준이 셋 있다. WCAG 2.2의 2.3.3 상호작용에 의한 애니메이션(AAA)은 사람의 조작(스크롤, 누름)으로 일어나는 움직임을, 그것이 기능이나 정보 전달에 꼭 필요한 경우가 아니라면 끌 수 있게 하라고 한다. 등급은 가장 높은 AAA라 법적·계약상 요구에서 빠지는 경우가 많지만, 시차 스크롤 같은 효과에 정확히 해당한다. 2.2.2 일시 정지, 정지, 숨기기(A)는 저절로 시작해 5초 넘게 움직이는 내용(자동으로 넘어가는 배너 등)을 멈추거나 숨길 수 있게 하라고 한다. 2.3.1 세 번의 번쩍임 또는 그 이하(A)는 1초에 세 번 넘게 번쩍이는 것을 금지한다. 광과민성 발작을 일으킬 수 있기 때문이다.

자동으로 도는 배너 첫 화면의 사진이 몇 초마다 저절로 옆으로 넘어가는 배너(캐러셀)는 많은 사이트에 있지만 문제가 많다. 사람이 다 읽기 전에 넘어가고, 화면의 넓은 면적이 주기적으로 움직이며, 화면 낭독기 사용자는 내용이 바뀌는 것을 알기 어렵다. 5초 넘게 저절로 움직인다면 2.2.2에 따라 멈춤 단추가 있어야 한다. 대부분의 경우 가장 중요한 것 하나를 고정해서 보여 주는 편이 낫다. 2장에서 서윤이 첫 화면에 "다음 모임" 하나만 두기로 한 것도 같은 판단이다.

줄인 움직임 선호

운영 체제의 "동작 줄이기" 설정을 켜면, 브라우저는 그 사실을 웹 페이지에 미디어 쿼리(Media query)로 알려 준다. 미디어 쿼리는 화면 폭이나 색 테마 같은 보는 환경의 조건에 따라 다른 CSS를 적용하는 장치다(5장). 움직임 설정을 알려 주는 조건이 prefers-reduced-motion이고 값은 reduce(줄여 달라)와 no-preference(따로 설정 없음) 둘이다. W3C의 Media Queries Level 5에 정의되어 있고 주요 브라우저가 모두 지원한다.

:root {
  --motion-base: 250ms;
  --ease-out: cubic-bezier(0, 0, 0.58, 1);
}
.menu {
  transition: transform var(--motion-base) var(--ease-out),
              opacity var(--motion-base) var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .menu {
    transition: opacity 150ms linear;   /* 이동은 빼고 나타남만 남긴다 */
    transform: none;
  }
  html { scroll-behavior: auto; }       /* 부드러운 스크롤도 끈다 */
}

스크립트에서도 같은 값을 읽을 수 있다. window.matchMedia("(prefers-reduced-motion: reduce)").matches가 true이면 줄여 달라는 뜻이다. 이 장 맨 위의 스위치가 바로 이 값을 읽고, 설정이 바뀌는 순간(change 이벤트)에도 따라 바뀐다. 자바스크립트로 만든 움직임(스크롤 이동, 캔버스 애니메이션, 자동 재생 영상)은 CSS의 미디어 쿼리가 막아 주지 않으므로 스크립트에서 직접 확인해야 한다.

"줄인다"는 말을 "모두 없앤다"로 읽으면 안 된다. 움직임이 하던 일(상태 변화 알림, 공간 관계)은 여전히 필요하다. 아래 시뮬레이터에서 왼쪽은 보통의 전환, 오른쪽은 움직임을 줄인 사람이 보게 될 전환이다. 오른쪽의 방법을 바꿔 가며 비교한다.

SIMULATOR

줄인다는 것은 바꾸는 것

오른쪽의 움직이는 거리—
오른쪽의 시간—
남는 단서—
해볼 것: ① "짧은 페이드"로 둘 다 연다. 왼쪽은 패널이 단추에서 펼쳐지고, 오른쪽은 제자리에서 150ms 동안 나타난다. 움직이는 거리는 0이지만 "새로 나타났다"는 것은 보인다. ② "모두 끔"으로 바꾼다. 패널이 순간적으로 생긴다. 줄인 움직임 설정을 지켰지만, 작은 변화라면 놓칠 수도 있다. ③ "짧은 이동 + 페이드"는 8px만 내려오며 나타난다. 방향의 단서를 조금 남기면서 큰 이동은 없앤다. ④ "그대로 둠"은 설정을 무시한 것이다. (왼쪽은 이 장 케이스의 값: 250ms, 단추에서 펼침. 오른쪽의 이동 거리는 목업 화소다. 어느 정도의 짧은 이동까지 괜찮은지는 사람마다 달라, 지침들은 대체로 이동·확대·회전을 빼고 페이드로 바꾸는 쪽을 권한다.)

시뮬레이터의 네 방법 가운데 정답은 상황마다 다르지만, 원칙은 분명하다. 움직임을 줄인 사람에게는 이동, 확대, 회전, 시차를 빼고, 상태 변화는 짧은 페이드나 색 변화처럼 넓은 면이 움직이지 않는 방법으로 알린다. 포커스 표시, 눌림 표시, 진행 막대처럼 정보를 전하는 작은 변화는 남긴다. 반대로 설정이 없는 사람에게도 화면 전체가 날아다니는 움직임을 기본으로 두지 않는다. 줄인 움직임 설정을 켜는 사람은 불편을 느끼는 사람 가운데 일부일 뿐이다. 설정이 있는 줄도 모르는 사람이 훨씬 많다.

서윤의 웹 개편 노트

CASE 서윤웹 개편 노트 · 10장

움직임 두 단계, 곡선 하나

2월 셋째 주, 지후가 들뜬 얼굴로 시험 주소를 보냈다. "움직임을 좀 넣어 봤어요." 첫 화면 서점 사진은 스크롤하면 글자보다 느리게 따라오며 커졌고, 휴대폰의 "더보기" 패널은 화면 왼쪽 밖에서 회전하며 날아와 600ms 동안 출렁이다 멈췄다. 신간 목록의 카드 열두 장은 120ms 간격으로 하나씩 아래에서 떠올랐다(한 장에 400ms). 9장에서 정한 신청 폼은 "신청하기"를 누르면 접히고, 완료 카드가 위로 튀어 올랐다.

서윤의 노트북에서는 꽤 근사했다. 그런데 도경이 휴대폰으로 열자 표정이 굳었다. 글자를 크게 키운 도경의 화면에서는 사진이 화면의 절반을 넘게 차지해, 스크롤할 때마다 화면 대부분이 출렁였다. 신간 목록을 열고는 "마지막 책을 누르려는데 아직 안 나와"라고 했다. 이 장의 계산으로 열한 번의 간격에 한 장의 전환을 더하면 1.72초다. 더보기 패널이 두 번째로 날아왔을 때 도경은 휴대폰을 내려놓았다. "배 탄 것 같아."

지후는 서운해했지만 금방 고개를 끄덕였다. "제 화면에서는 몰랐어요. 제 휴대폰엔 동작 줄이기가 꺼져 있고, 화면도 작게 보니까." 셋은 지후가 넣은 움직임을 하나씩 이 장의 네 가지 일(상태 변화 알림, 공간 관계, 주의 끌기, 연속성)에 대 보았다. 어디에도 들지 않는 것은 지우고, 남긴 것은 시간과 곡선을 정해 토큰으로 묶었다.

움직임지후의 첫 시도서윤의 선택
시간 토큰요소마다 제각각(300~800ms)--motion-short: 150ms(눌림·호버·체크·닫힘), --motion-base: 250ms(열림·펼침·나타남) 두 단계만
이징 토큰튕김, 탄성, ease 섞어 씀--ease: cubic-bezier(0.2, 0, 0, 1) 하나(빨리 출발해 부드럽게 멈추는 감속). 열림·닫힘·자리 옮김 모두 이 곡선
더보기 패널왼쪽 밖에서 회전하며 날아와 출렁임, 600ms단추 아래 오른쪽 모서리에서 펼침 250ms, 닫힘은 단추로 접히며 150ms
신간 카드120ms 간격 차례 등장, 한 장 400ms(마지막 1.72초)차례 등장 없음. 처음 열 때 목록 전체가 한 번에 페이드 150ms
카드 → 상세오른쪽에서 회전하며 들어옴누른 카드에서 커지는 전환 250ms, 뒤로 가면 그 카드로 돌아감
첫 화면 사진시차 스크롤 + 확대둘 다 없앰. 사진은 글자와 함께 스크롤
신청 완료 카드폼이 접히고 카드가 튀어 오름폼 자리에 완료 카드가 16px 아래에서 올라오며 나타남 250ms, 포커스를 완료 문장으로 옮김
줄인 움직임 선호고려하지 않음이동·확대 모두 opacity 150ms 페이드로 바꿈, 부드러운 스크롤 끔. 눌림·포커스 표시는 그대로

곡선을 고를 때 서윤은 편집기에서 ease-out과 cubic-bezier(0.2, 0, 0, 1)을 나란히 돌려 보았다. 두 번째 곡선은 출발이 조금 더 빠르고 끝이 더 길게 가라앉아, 250ms 안에서도 "도착"이 분명했다. 지후는 닫힘에 가속 곡선을 따로 두자고 했지만, 서윤은 이번에는 곡선 하나로 시작하고 닫힘은 시간을 짧게 해서 해결하기로 했다. 토큰이 적을수록 나중에 화면을 늘릴 때 고민이 적다. 지후는 카드에서 상세로 커지는 전환을 남길 수 있어 기뻐했다. "이건 장식이 아니라 길 안내니까요."

바꾼 사이트를 도경이 다시 열었다. 더보기를 누르자 패널이 단추 밑에서 짧게 펼쳐졌다. 도경은 이번엔 아무 말 없이 메뉴를 골랐다. 서윤은 그게 칭찬이라는 것을 알았다.

이 장에서 정한 것시간 토큰 두 단계 --motion-short: 150ms, --motion-base: 250ms, 이징 토큰 하나 cubic-bezier(0.2, 0, 0, 1). 열림은 250ms, 닫힘은 150ms. 전환은 누른 곳에서 시작하고 그곳으로 돌아간다. 차례 등장·시차 스크롤·확대·회전·튕김은 쓰지 않는다. prefers-reduced-motion: reduce이면 이동과 확대를 150ms 페이드로 바꾸고 부드러운 스크롤을 끈다.
아직 남은 문제신청 폼의 오류와 완료 문장이 화면 낭독기에 제대로 읽히는지, 키보드만으로 메뉴를 열고 닫을 수 있는지, 포커스가 패널 안으로 들어가는지는 아직 확인하지 않았다. 도경의 지인인 단골손님이 화면 낭독기로 사이트를 써 보겠다고 했다.
다음 단계11장: 웹 접근성 점검.

핵심 정리

  1. 화면의 움직임은 상태 변화 알림, 공간 관계, 주의 끌기, 연속성의 일을 할 때 쓸모 있다. 어디에도 들지 않는 움직임은 장식이고, 매일 쓰는 화면에서는 기다림이 된다.
  2. 이징은 시간과 진행률을 잇는 함수다. 들어오는 것은 감속(ease-out), 나가는 것은 가속(ease-in), 화면 안에서 옮기는 것은 가감속(ease-in-out), 위치 없는 변화는 선형이 어울린다.
  3. CSS의 cubic-bezier(x1, y1, x2, y2)는 양 끝이 (0, 0)과 (1, 1)인 3차 베지에 곡선의 두 조절점이다. y가 1을 넘으면 오버슈트가 생긴다. 사이트 전체에서 곡선은 한두 개로 줄인다.
  4. 지속 시간은 대략 100~500ms(통설)에서 거리·크기·방향·빈도에 따라 고른다. 닫힘은 열림보다 짧게. 차례 등장의 총 시간은 \((n-1)d + T\)로 금세 1초를 넘는다.
  5. 전환은 출발점을 지켜야 공간 관계를 알려 준다. 메뉴는 누른 단추에서, 상세 화면은 누른 카드에서 시작하고 그곳으로 돌아간다.
  6. 넓은 면적의 움직임, 시차 스크롤, 확대·회전은 전정 장애가 있는 사람에게 어지럼증을 일으킬 수 있다. WCAG 2.2의 2.3.3(AAA), 2.2.2(A), 2.3.1(A)이 관련 기준이다.
  7. prefers-reduced-motion: reduce이면 움직임을 없애는 대신 바꾼다. 이동·확대·회전·시차를 빼고 짧은 페이드로 상태 변화를 남긴다. 스크립트로 만든 움직임은 matchMedia로 직접 확인한다.

확인 퀴즈

1. 화면 위쪽에서 알림 띠가 내려와 자리를 잡는다. 이 "들어오는" 움직임에 가장 어울리는 이징은?

들어오는 것은 감속이 어울린다. 빨리 출발해 반응이 빠르게 느껴지고, 눈앞에서 부드럽게 멈춰 도착한 자리가 분명하다. ease-in은 끝에서 가장 빠른 채로 부딪치듯 멈추어 나가는 움직임에 맞다. 선형은 위치가 있는 움직임에서 기계적으로 보이고, steps()는 끊기는 효과용이다.

2. 신간 카드 12장이 120ms 간격으로 하나씩 나타나고, 카드 한 장의 전환은 400ms다. 마지막 카드가 다 나타나는 시간은?

마지막 카드는 첫 카드보다 (12 − 1) × 120 = 1,320ms 늦게 출발하고, 출발한 뒤 400ms가 지나야 다 나타난다. 1,320 + 400 = 1,720ms. 520ms는 간격 하나와 전환 하나만 더한 것, 1,440ms는 간격을 12번 센 것, 4,800ms는 전환 시간을 12번 더한 것이다.

3. 휴대폰의 "더보기" 메뉴가 화면 왼쪽 밖에서 회전하며 날아와 600ms 동안 출렁이다 멈춘다. 이 장의 원칙에 가장 맞게 고친 것은?

전환은 누른 곳에서 시작해야 공간 관계를 알려 준다. 왼쪽에서 오는 메뉴는 회전을 빼도 출발점이 엉뚱하다. 시간을 늘리면 매번 기다리게 된다. 움직임을 모두 없애면 빠르지만 무엇이 어디서 왔는지 알려 주는 일까지 버리게 된다.

4. prefers-reduced-motion: reduce를 켠 사람에게 메뉴를 열어 보여 주는 방법으로 가장 알맞은 것은?

줄인 움직임은 정보를 줄이는 것이 아니라 전하는 방법을 바꾸는 것이다. 넓은 면이 움직이는 이동·확대·회전을 빼고 짧은 페이드로 상태 변화를 남긴다. 포커스나 눌림 표시는 움직임이 아니라 정보이므로 없애면 안 된다. 등급과 상관없이 사람이 직접 요청한 설정이고, 시간을 늘리면 움직임이 더 오래 보일 뿐이다.