반응형으로 배치를 자유롭게 바꾸게 되자, 나는 상태가 바뀌는 그 순간이 너무 딱딱하다는 걸 느끼기 시작했다. 버튼에 마우스를 올리면 색이 순식간에 바뀌고, 메뉴가 펼쳐지면 툭 하고 나타났다. 변화 자체는 맞는데 그 사이가 너무 급격했다. 시작과 끝 사이를 부드럽게 이어주는 무언가가 필요했고, 그게 바로 트랜지션이었다.


이번 편은 상태 변화를 부드럽게 보간하는 트랜지션을 다룬다. 트랜지션이 어떤 원리로 작동하는지, 어떤 속성과 시간과 곡선으로 그 변화를 조율하는지, 무엇을 애니메이션해야 성능이 좋은지, 그리고 부드러움을 남용하지 않는 절제까지 살펴본다. 이 작은 부드러움 하나가 화면 전체의 완성도를 얼마나 끌어올리는지 나는 여러 번 경험했다.

1. 상태와 상태 사이를 채우기

트랜지션은 어떤 속성의 값이 바뀔 때, 그 변화를 즉시가 아니라 시간을 두고 서서히 진행시키는 기능이다. 평소 상태와 마우스를 올린 상태처럼 두 상태의 값이 다를 때, 트랜지션은 그 사이의 중간값들을 자동으로 계산해 채운다. 나는 이 중간값을 채우는 과정을 보간이라고 이해하고 나서, 트랜지션이 하는 일이 명확해졌다.


중요한 점은 트랜지션이 두 상태를 스스로 만들지는 않는다는 것이다. 트랜지션은 이미 존재하는 값의 변화를 부드럽게 이어줄 뿐, 상태를 바꾸는 계기는 따로 있어야 한다. 마우스를 올리는 상태, 포커스가 들어온 상태, 혹은 요소에 특정 표시가 붙는 것 같은 계기가 값을 바꾸면, 트랜지션이 그 변화를 시간에 걸쳐 펼친다. 나는 이 역할 분담을 이해하는 게 첫걸음이라고 본다.


트랜지션은 원래 상태로 돌아올 때도 작동한다. 마우스를 올렸다 뗄 때, 값이 원위치로 돌아가는 과정 역시 부드럽게 이어진다. 나는 이 왕복의 대칭성이 트랜지션을 자연스럽게 만든다고 느낀다. 들어갈 때만 부드럽고 나올 때는 툭 끊기면 어색한데, 트랜지션은 양방향을 모두 매끄럽게 처리해 준다.


모든 속성이 부드럽게 변할 수 있는 건 아니다. 색이나 크기, 위치처럼 중간값이 존재하는 속성은 잘 보간되지만, 중간 상태가 없는 속성은 부드럽게 이어지지 않고 갑자기 바뀐다. 나는 처음에 이 구분을 몰라서, 어떤 속성은 트랜지션이 먹고 어떤 속성은 안 먹는 이유를 한참 몰랐다. 연속적인 값을 가진 속성만 보간된다는 원리를 알면 이 혼란이 풀린다.


트랜지션은 하나의 요소에 여러 속성을 동시에 걸 수도 있다. 색과 위치를 함께 부드럽게 바꾸거나, 각 속성마다 다른 시간을 줄 수도 있다. 나는 버튼에 마우스를 올릴 때 배경색과 위치를 동시에 전환해서, 색이 진해지며 살짝 떠오르는 효과를 자주 쓴다. 여러 변화가 한꺼번에 조화롭게 일어나면 화면이 살아 있는 느낌을 준다.


트랜지션의 매력은 마크업을 전혀 건드리지 않는다는 데 있다. 오직 스타일에서 상태 간 값의 차이를 정의하고 트랜지션을 거는 것만으로 부드러운 움직임이 생긴다. 나는 자바스크립트 없이 순수하게 스타일만으로 이만한 효과를 낼 수 있다는 점에서 트랜지션을 아낀다. 가장 적은 비용으로 화면의 완성도를 크게 높이는 도구다.

2. 트랜지션을 이루는 네 가지

트랜지션을 정하려면 네 가지를 지정한다. 어떤 속성을 전환할지, 얼마 동안 진행할지, 어떤 곡선으로 진행할지, 그리고 얼마나 기다렸다 시작할지다. 이 네 가지가 트랜지션의 성격을 결정한다. 나는 처음에 지속 시간만 신경 썼는데, 나머지 세 가지를 조율하기 시작하면서 훨씬 세밀한 표현이 가능해졌다.


첫째는 어떤 속성을 전환할지 고르는 것이다. 특정 속성만 지정할 수도 있고, 변하는 모든 속성을 한꺼번에 전환하게 할 수도 있다. 나는 되도록 전환할 속성을 명시적으로 지정하는 편이다. 모든 속성을 뭉뚱그려 전환하면, 의도치 않은 값까지 부드럽게 변하면서 예상 못 한 움직임이 생기거나 성능에 부담이 될 수 있기 때문이다.


둘째는 지속 시간이다. 변화가 얼마나 오래 걸릴지를 정하는데, 이 값이 트랜지션의 인상을 크게 좌우한다. 너무 짧으면 부드러움이 느껴지지 않고, 너무 길면 답답하고 반응이 굼떠 보인다. 나는 대부분의 상호작용에 짧고 경쾌한 시간을 준다. 사용자의 동작에 즉각 반응하는 느낌을 주면서도, 딱딱하지 않을 만큼의 부드러움을 남기는 지점을 찾는다.


셋째는 진행 곡선을 정하는 타이밍 함수다. 같은 시간이라도 처음에 빠르다 끝에 느려지는지, 아니면 일정한 속도로 진행하는지에 따라 느낌이 완전히 달라진다. 나는 이 곡선이 트랜지션의 성격을 결정하는 핵심이라고 본다. 시간과 속성이 무엇을 얼마나 바꾸는지를 정한다면, 곡선은 그 변화가 어떤 태도로 일어나는지를 정한다.


넷째는 지연이다. 값이 바뀐 뒤 곧바로 전환을 시작하지 않고 잠시 기다리게 할 수 있다. 나는 여러 요소가 연달아 나타나는 효과를 만들 때 각 요소에 조금씩 다른 지연을 줘서, 하나씩 차례로 등장하는 느낌을 낸다. 지연을 잘 쓰면 단순한 동시 변화가 리듬감 있는 순차적 움직임으로 바뀐다. 다만 지연이 너무 길면 반응이 늦다는 인상을 주니 조심한다.


이 네 가지는 하나의 간결한 표현으로 묶어 적을 수도 있다. 속성, 시간, 곡선, 지연을 순서대로 나열하면 한 줄로 트랜지션을 정의할 수 있다. 나는 여러 속성에 서로 다른 설정을 주고 싶을 때, 각각의 트랜지션을 나눠 적어 관리한다. 간결함과 명확함 사이에서 상황에 맞게 표현 방식을 고르면 코드가 읽기 좋아진다.

3. 변화의 태도를 정하는 타이밍 함수

타이밍 함수는 트랜지션이 진행되는 속도의 변화를 정의한다. 처음부터 끝까지 같은 속도로 갈 수도 있고, 천천히 시작해 빨라질 수도, 빠르게 시작해 느려질 수도 있다. 이 속도 곡선이 움직임의 인상을 결정한다. 나는 같은 트랜지션이라도 곡선만 바꾸면 완전히 다른 느낌이 난다는 걸 알고 나서, 이 함수를 진지하게 다루기 시작했다.


일정한 속도로 진행하는 곡선은 기계적이고 단조로운 느낌을 준다. 회전하는 로딩 표시처럼 균일한 움직임이 어울리는 곳에는 이 곡선이 맞다. 하지만 대부분의 상호작용에는 어색하다. 현실의 물체는 갑자기 최고 속도로 움직이지 않고 가속과 감속을 거치기 때문이다. 나는 균일한 속도를 특별한 경우가 아니면 잘 쓰지 않는다.


가장 자연스럽게 느껴지는 것은 시작과 끝에서 부드럽게 가속하고 감속하는 곡선이다. 천천히 출발해 중간에 빨라졌다가 끝에서 다시 느려지는 이 움직임은 현실의 감각과 닮아 편안하다. 나는 특별한 의도가 없다면 대부분의 트랜지션에 이런 완만한 가감속 곡선을 기본으로 쓴다. 사용자에게 가장 익숙하고 거슬리지 않는 움직임이기 때문이다.


끝에서 감속하는 곡선은 요소가 등장할 때 잘 어울린다. 빠르게 들어와 부드럽게 자리를 잡는 느낌을 주기 때문이다. 반대로 시작에서 가속하는 곡선은 요소가 사라질 때 어울린다. 나는 나타남과 사라짐에 서로 다른 곡선을 써서, 등장은 시원하게 퇴장은 미련 없이 처리한다. 방향에 맞는 곡선을 고르면 움직임에 의도가 담긴다.


원하는 곡선을 직접 정의할 수도 있다. 몇 개의 조절점으로 속도 곡선의 모양을 세밀하게 빚거나, 값이 단계적으로 뚝뚝 끊기며 변하는 곡선을 만들 수도 있다. 나는 통통 튀는 듯한 탄력적인 느낌이 필요할 때 곡선을 직접 조율한다. 다만 지나치게 개성적인 곡선은 오히려 산만하니, 대부분은 검증된 무난한 곡선 안에서 해결한다.


타이밍 함수는 눈에 잘 띄지 않지만 화면의 인격을 만든다. 같은 사이트라도 움직임의 곡선이 일관되면 정돈된 인상을 주고, 제각각이면 산만해 보인다. 나는 프로젝트 전체에서 쓰는 곡선을 몇 가지로 정해두고 일관되게 적용한다. 색과 글꼴을 통일하듯 움직임의 태도도 통일해야 화면 전체가 하나의 언어로 말하게 된다.

4. 무엇을 전환해야 성능이 좋을까

트랜지션에서 흔히 간과하는 것이 성능이다. 어떤 속성을 애니메이션하느냐에 따라 브라우저가 치르는 비용이 크게 다르다. 나는 부드러워 보이던 화면이 어떤 기기에서는 뚝뚝 끊기는 걸 보고, 무엇을 전환하느냐가 성능을 좌우한다는 사실을 배웠다. 움직임의 부드러움은 곡선만이 아니라 대상 선택에서도 나온다.


화면에 무언가를 그리는 과정은 크게 배치 계산, 색칠, 합성의 단계로 나뉜다. 요소의 크기나 위치를 바꾸면 배치부터 다시 계산해야 하므로 비용이 가장 크다. 이 배치 계산은 주변 요소들에까지 영향을 미쳐 연쇄적으로 다시 계산을 유발한다. 나는 너비나 위쪽 여백 같은 값을 애니메이션했다가 화면이 버벅이는 걸 겪고 이 비용을 실감했다.


반면 요소의 변형과 투명도는 배치 계산 없이 처리된다. 요소를 옮기거나 키우거나 회전시키는 변형, 그리고 투명하게 만드는 것은 이미 그려진 결과를 합성 단계에서 조정하는 것에 가깝다. 그래서 이 두 가지는 부드럽게 애니메이션되며 성능 부담이 적다. 나는 움직임이 필요할 때 위치를 직접 바꾸는 대신 변형으로 옮기는 습관을 들였다.


구체적으로, 요소를 이동시키고 싶으면 위치 속성 대신 변형으로 옮기고, 크기를 바꾸고 싶으면 너비 대신 변형의 확대를 쓴다. 나타나고 사라지는 효과는 투명도로 처리한다. 나는 이 원칙을 세운 뒤로, 애니메이션이 저사양 기기에서도 매끄럽게 도는 걸 확인했다. 같은 결과를 내면서도 비용이 훨씬 적은 길이 대개 존재한다.


브라우저에 미리 준비를 시키는 힌트도 있다. 곧 어떤 속성이 변할 거라고 미리 알려주면 브라우저가 해당 요소를 별도로 최적화해 둔다. 다만 이 힌트를 상시로 남발하면 오히려 메모리를 낭비하고 부작용을 낳는다. 나는 이 힌트를 정말 무거운 애니메이션 직전에만 최소한으로 쓰고, 끝나면 거둬들인다. 최적화 힌트는 약이자 독이다.


성능을 챙기는 가장 확실한 방법은 실제로 확인하는 것이다. 개발 도구로 애니메이션 중에 배치 계산이 반복되는지 살피면, 비용이 큰 속성을 쓰고 있는지 금방 드러난다. 나는 중요한 애니메이션은 저사양 환경을 흉내 내어 점검한다. 내 좋은 기기에서만 부드러운 화면은 절반의 성공일 뿐이다. 모든 사용자에게 부드러워야 진짜 부드러운 것이다.

5. 부드러움을 절제하는 감각

트랜지션을 배우고 나면 모든 것에 부드러움을 넣고 싶은 유혹이 생긴다. 나도 한때 온갖 요소에 전환 효과를 걸었다가, 화면이 오히려 산만하고 굼떠 보이는 역효과를 냈다. 움직임은 시선을 끌기 때문에, 곳곳에서 무언가가 계속 움직이면 사용자가 무엇에 집중해야 할지 알 수 없게 된다. 부드러움도 지나치면 소음이 된다.


좋은 트랜지션은 사용자의 행동에 대한 반응으로만 등장하는 것이 좋다. 마우스를 올리거나 무언가를 열고 닫는 것처럼, 사용자가 일으킨 변화를 이해하기 쉽게 이어주는 역할에 충실해야 한다. 나는 사용자가 요청하지 않은 자발적인 움직임은 최대한 자제한다. 트랜지션은 주인공이 아니라, 상태 변화를 매끄럽게 설명하는 조연이어야 한다.


지속 시간의 절제도 중요하다. 상호작용에 대한 반응은 짧아야 한다. 사용자는 자신의 동작에 즉각적인 피드백을 기대하는데, 전환이 길면 시스템이 굼뜨다고 느낀다. 나는 클릭이나 마우스 반응처럼 즉각성이 중요한 곳에는 아주 짧은 시간을, 화면이 크게 전환되는 곳에는 조금 더 긴 시간을 준다. 변화의 규모에 시간을 맞추는 것이다.


움직임에 민감한 사용자를 위한 배려도 잊지 말아야 한다. 앞선 편에서 다룬, 움직임을 줄이고 싶어 하는 사용자의 설정을 감지해 트랜지션을 줄이거나 없애는 대비를 함께 둔다. 나는 새 전환 효과를 넣을 때마다 이 대비를 습관처럼 붙인다. 누군가에게 즐거움인 움직임이 다른 누군가에게는 어지럼증이 될 수 있다는 걸 늘 염두에 둔다.


트랜지션과 다음 편에서 다룰 애니메이션의 경계도 알아두면 좋다. 트랜지션은 두 상태 사이를 잇는 단순한 변화에 어울리고, 여러 단계를 거치거나 스스로 반복되는 복잡한 움직임에는 애니메이션이 맞다. 나는 상태가 둘뿐인 단순한 변화라면 트랜지션으로 충분하다고 판단한다. 도구를 상황에 맞게 고르는 것이 과한 복잡함을 피하는 길이다.


정리하면 트랜지션은 상태 사이를 시간과 곡선으로 부드럽게 잇는 도구이고, 무엇을 전환하느냐로 성능이 갈리며, 절제할수록 효과가 산다. 나는 변형과 투명도를 짧고 자연스러운 곡선으로 전환하는 것을 기본 습관으로 삼는다. 이 작은 부드러움이 딱딱한 화면을 살아 있게 만든다. 다음 편에서는 여러 단계를 스스로 밟아가는 더 풍부한 움직임, 애니메이션을 다룬다.