트랜지션과 애니메이션


버튼에 :hover 색상을 추가하면 동작은 하지만 변화가 뚝뚝 끊깁니다. 한 프레임에서는 파란색이고 다음 프레임에서는 어두운 색인데, 그 중간 과정이 없기 때문입니다. 아주 살짝만 페이드를 넣어줘도 페이지 전체가 훨씬 덜 뻣뻣하게 느껴집니다. 이 페이드가 바로 트랜지션이며, 두 상태 사이의 움직임을 표현할 수 있게 되면 같은 도구를 확장해서 호버 효과, 위로 떠오르는 카드, 로딩 중에 회전하는 스피너까지 만들 수 있습니다. 이 장에서는 CSS가 요소를 어떻게 움직이는지, 그리고 페이지를 더 쓰기 어렵게 만들지 않으면서 움직이는 방법을 다룹니다.
트랜지션
**트랜지션(transition)**은 속성 값이 바뀔 때 옛 값에서 새 값으로 뚝 끊기지 않고 애니메이션하도록 브라우저에 지시합니다. 평상시 상태와 호버 상태, 이렇게 두 상태를 정해두면 트랜지션이 그 중간 프레임들을 채워줍니다.
호버 시 색이 바뀌는 버튼을 예로 들어보겠습니다. 트랜지션이 없으면 색이 순간적으로 바뀌고, 있으면 서서히 바뀝니다.
.btn {
background: #3b82f6;
transition: background 0.2s; /* 0.2초에 걸쳐 색을 서서히 바꿈 */
}
.btn:hover {
background: #1d4ed8; /* 애니메이션이 향할 새 상태 */
}transition은 평상시 상태에 지정하며, :hover에는 넣지 않습니다. 그래야 마우스가 들어올 때와 나갈 때 모두 적용됩니다.
:hover가 아니라 평상시 상태에 작성해야 들어갈 때와 나갈 때 모두 동작합니다. property와 duration만 있어도 이미 동작하는 페이드가 완성됩니다. Transform
**transform**은 주변에 아무런 영향을 주지 않으면서 요소를 이동, 확대/축소, 회전시킵니다. 대개 애니메이션하고 싶은 대상이 바로 이것인데, 부드럽게 보이고 주변 요소를 밀어내지 않기 때문입니다.
자주 쓰게 될 세 가지가 있습니다:
.card:hover {
transform: translateY(-4px); /* 위로 4픽셀 이동 */
}
.icon:hover {
transform: scale(1.1); /* 원래 크기의 110%로 확대 */
}
.arrow.open {
transform: rotate(90deg); /* 시계 방향으로 4분의 1바퀴 회전 */
}translate는 이동, scale은 크기 조절, rotate는 회전을 담당합니다. 이 중 하나를 트랜지션과 짝지으면 위로 떠오르는 카드, 튀어오르는 아이콘, 활짝 펴지는 화살표를 만들 수 있습니다.
transform은 주변 요소를 밀어내지 않으면서 요소를 이동, 확대/축소, 회전시킵니다. 기억해야 할 세 가지는 이동하는 translate, 크기를 조절하는 scale, 회전시키는 rotate입니다. 트랜지션과 결합하면 호버 시 떠오르는 카드나 튀어오르는 아이콘을 만들 수 있습니다. 키프레임 애니메이션
트랜지션은 두 상태 사이를 애니메이션합니다. 두 상태보다 더 많은 단계가 필요하거나 동작이 반복되어야 할 때는 **키프레임 애니메이션(keyframe animation)**을 씁니다. @keyframes로 단계를 작성한 다음, animation 속성으로 그 단계들을 요소에 연결합니다.
로딩 스피너가 전형적인 예입니다. 계속 회전해야 하므로 트랜지션으로는 불가능합니다.
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite; /* spin 실행, 한 바퀴에 1초, 무한 반복 */
}from은 시작, to는 끝입니다. animation 줄에는 어떤 키프레임을 실행할지, 한 주기가 얼마나 걸릴지, 속도 곡선, 몇 번 반복할지를 지정합니다. infinite는 절대 멈추지 않는다는 뜻입니다.
@keyframes에 단계를 작성하고 animation으로 실행하세요. 스피너가 대표적인 예입니다. 0도인 from, 360도인 to, 그리고 infinite로 반복합니다. animation 줄에는 어떤 키프레임, 얼마 동안, 어떤 곡선, 몇 번 반복할지를 지정합니다. 사용자를 존중하는 동작
모든 사람이 화면에서 움직임을 원하는 건 아닙니다. 어떤 사람에게는 산만하게 느껴지고, 어떤 사람에게는 실제로 불편함이나 멀미를 유발할 수도 있습니다. 브라우저는 시스템 설정에서 동작을 줄여달라고 요청할 수 있게 해주며, CSS는 **prefers-reduced-motion**으로 이 요청을 읽을 수 있습니다.
동작을 줄여달라고 요청하지 않은 사람에게만 애니메이션이 실행되도록 애니메이션을 조건문으로 감싸세요.
@media (prefers-reduced-motion: no-preference) {
.card {
transition: transform 0.2s;
}
}사용자를 존중하는 데 있어 나머지 절반은 절제입니다. 동작을 짧고 은은하게 유지하고, 호버나 클릭처럼 독자가 실제로 한 행동과 연결시키세요. 실제 변화에 주의를 끄는 동작은 도움이 되지만, 그저 장식용 동작은 금방 지겨워집니다.
prefers-reduced-motion으로 이를 읽어서 동작을 줄이지 않은 사람에게만 애니메이션을 실행하세요. 그리고 추가하는 동작 자체도 짧고 은은하게, 독자가 실제로 한 행동과 연결되도록 유지하세요. 무엇을 애니메이션할지, 그리고 왜 그것이 중요한지
나중에 골치 아픈 일을 줄여줄 간단한 규칙 하나: 움직임을 애니메이션할 때는 width, height, top, margin 같은 속성이 아니라 transform과 opacity를 애니메이션하세요.
/* 부드러움: 브라우저가 저렴하게 처리 */
.card:hover {
transform: translateY(-4px);
opacity: 0.9;
}이유는 transform과 opacity가 브라우저가 가장 저렴하게 움직일 수 있는 두 속성이기 때문입니다. 그래서 이 두 속성을 기반으로 만든 애니메이션은 느린 기기에서도 매끄럽게 유지됩니다. 크기나 위치 속성을 애니메이션하면 브라우저가 매 프레임마다 더 많은 작업을 해야 하고, 동작이 뚝뚝 끊길 수 있습니다. 더 깊이 파고들 때 전체 이유를 만나게 되겠지만, 이 습관은 지금부터 들여둘 만한 가치가 있습니다.
transform과 opacity를 애니메이션하고, width, height, top, margin을 애니메이션하는 건 피하세요. 이 두 속성이 브라우저가 움직이기에 가장 저렴하므로, 느린 기기에서도 동작이 매끄럽게 유지됩니다. 전체 이유는 나중에 배우게 되겠지만, 이 습관은 지금부터 시작할 만한 가치가 있습니다. 
