CSS 애니메이션(CSS Animations)과 트랜지션(Transitions)은 '애니메이션 가능한(animatable)' 속성이라는 개념을 바탕으로 작동합니다. 그리고 따로 명시되어 있지 않는 한, 기본적으로 모든 CSS 속성은 애니메이션이 가능합니다.
각 속성이 가진 애니메이션 타입(animation type)은 해당 속성의 값들이 어떻게 결합(combine)될지(보간(interpolate), 추가(add), 또는 누적(accumulate))를 결정합니다. 트랜지션은 오직 '보간(interpolation)' 방식만 관여하는 반면, 애니메이션은 이 세 가지 결합 방식을 모두 사용할 수 있습니다.
💡 강사 팁:
Next.js나 React 같은 환경에서 컴포넌트 주도 개발을 하실 때, 단순한 마우스 오버(Hover) 효과에는 상태 변화 없이 CSS '트랜지션'을 쓰는 것이 깔끔합니다. 반면, 웹 프로필 사이트의 메인 화면에 들어갈 때 요소들이 순차적으로 날아오는 복잡한 연출을 할 때는@keyframes를 활용한 전체 '애니메이션'이 제어하기 훨씬 좋습니다.
참고:
각 CSS 속성의 애니메이션 타입은 공식 문서의 "형식 정의(Formal definition)" 표에 명시되어 있습니다 (예:color).
참고:
각 CSS 데이터 타입의 보간(Interpolation) 방식은 문서의 "보간(Interpolation)" 섹션에 설명되어 있습니다 (예:<length>).
웹 애니메이션(Web Animations) 명세서에 정의된 애니메이션 타입은 크게 네 가지가 있습니다:
애니메이션 불가 (Not animatable) 이 속성은 애니메이션을 적용할 수 없습니다. 애니메이션 키프레임(keyframe) 목록에 적어두더라도 무시되며, 트랜지션의 영향도 받지 않습니다.불연속적 (Discrete) 이 속성의 값들은 서로 점진적으로 더해질 수 없으며(not additive), 애니메이션 진행률이 딱참고: 애니메이션이 불가능한 속성만을 타겟으로 애니메이션 효과를 주더라도, 애니메이션과 관련된 일반적인 동작(예를 들어,
animationstart이벤트가 트리거되는 등)은 여전히 정상적으로 발생합니다.
50%가 되는 지점에서 시작 값에서 끝 값으로 확 바뀝니다(swaps). 진행률 값을 p라고 할 때 구체적으로 다음과 같이 동작합니다:
p < 0.5 이면, 결과값(V_result) = 시작값(V_start);p >= 0.5 이면, 결과값(V_result) = 끝값(V_end).계산된 값에 따라 (By computed value) 계산된 값(computed value)을 구성하는 개별 요소들이 해당 값 타입에 지정된 절차에 따라 서로 부드럽게 결합됩니다. 만약 구성 요소의 개수가 다르거나, 대응하는 구성 요소끼리 타입이 맞지 않거나, 혹은 어떤 구성 요소 값이든 '불연속적(Discrete)' 방식을 써야 하는데 두 값이 일치하지 않는다면, 이 속성 값들은 결국 불연속적(Discrete)인 방식으로 결합되어 뚝 끊기며 전환됩니다. 반복 가능한 목록 (Repeatable list) 기본적으로 '계산된 값에 따라' 방식과 동일합니다. 다만 두 목록의 항목 개수가 다를 경우, 먼저 두 항목 개수의 최소공배수가 될 때까지 목록을 반복해서 길이를 똑같이 맞춥니다. 그런 다음 각 항목을 '계산된 값에 따라' 부드럽게 결합합니다. 만약 값의 쌍을 결합할 수 없거나 어떤 구성 요소라도 '불연속적(Discrete)' 애니메이션을 사용한다면, 전체 속성 값은 불연속적으로 결합됩니다.💡 강사 팁:
마치 전구 스위치를 켜고 끄는 것과 같습니다.display: none에서display: block으로 바꿀 때, 서서히 투명해지며 나타나는 대신 뚝 끊기며 확 나타나버리죠? 바로display속성이 이 'Discrete' 타입이기 때문입니다. 이런 요소에 부드러운 전환을 주려면opacity나 방금 배운@starting-style같은 다른 우회로를 찾아야 합니다.
일부 속성들은 이 네 가지 타입으로 완전히 설명되지 않는 고유한 보간(interpolation) 동작을 가지고 있습니다. 이 경우에는 해당 속성 문서의 "보간(Interpolation)" 섹션을 참조하시기 바랍니다 (예: visibility).
registerProperty() 메서드를 사용하여 브라우저에 등록해 둔 사용자 지정 속성(CSS 변수)의 경우, 애니메이션 타입은 '계산된 값에 따라(by computed value)'가 되며, 계산된 값의 타입은 속성의 구문(syntax) 정의에 의해 결정됩니다.
반대로 등록되지 않은 사용자 지정 속성의 경우, 애니메이션 타입은 무조건 '불연속적(discrete)'입니다.
💡 강사 팁:
독후감 사이트나 개인 포트폴리오를 만드실 때, 다크 모드나 테마 색상 등을 제어하기 위해 CSS 변수(var(--main-color))를 많이 사용하실 텐데요. 이 CSS 변수에 트랜지션 애니메이션을 먹이고 싶다면 반드시@property나 JS의registerProperty()를 사용해 "이 변수는 색상(color)이야!"라고 브라우저에 알려주어야 합니다. 안 그러면 색이 서서히 변하지 않고 뚝뚝 끊기면서 변하게 됩니다!
transition-behavior@starting-style공식 문서의 용어들이 원래 학술적이고 번역투가 많아서 처음 읽으면 외계어처럼 느껴지는 게 당연합니다! "보간", "불연속적", "계산된 값" 같은 단어들 때문에 더 헷갈리셨을 거예요.
문서에서 계속 말하는 '보간(Interpolate)'이라는 단어는 쉽게 말해 '시작과 끝 사이의 중간 과정을 브라우저가 알아서 부드럽게 그려주는 것'을 뜻합니다.
0px에서 100px로 커질 때, 우리가 1px, 2px, 3px... 일일이 다 적어주지 않아도 브라우저가 알아서 스르륵 커지게 만들어주죠? 이게 바로 '보간'입니다.말 그대로 애니메이션을 아예 먹일 수 없는 속성들입니다.
font-family, background-image(이미지 URL 자체를 서서히 바꿀 순 없죠)부드러운 중간 과정 없이, 시간이 정확히 절반(50%) 흘렀을 때 모양이 '휙!' 하고 돌변하는 속성들입니다.
display, justify-content, positiondisplay: none;과 display: block; 사이의 중간 상태(반쯤 사라진 상태?)라는 건 브라우저 입장에서 존재하지 않기 때문입니다. 그래서 50%가 되는 시점에 뚝 끊기듯 변해버립니다.우리가 가장 잘 아는, 스르륵 부드럽게 변하는(보간되는) 속성들입니다.
width, height, color, opacity, transform10px에서 50px로는 부드럽게 커지지만, 10px에서 auto로는 중간값을 계산할 수 없어서 '불연속적(Discrete)'으로 뚝 끊기며 변하게 됩니다.box-shadow나 background처럼 쉼표(,)를 써서 여러 개의 값을 겹쳐서 쓰는 속성들입니다.
강사 팁에 나온 아주 중요한 내용입니다. 우리가 흔히 쓰는 CSS 변수(--my-color, --my-size 등)에 애니메이션을 줄 때 겪는 흔한 실수에 대한 이야기입니다.
❌ 일반적인 CSS 변수 (등록되지 않음)
:root {
--main-color: red; /* 브라우저: "이게 빨간색이야? 그냥 'red'라는 텍스트야?" */
}
브라우저는 기본적으로 사용자가 만든 변수 안에 들어있는 게 숫자인지, 색상인지, 단순한 글자인지 모릅니다. 그래서 중간값을 계산할 수 없기 때문에 무조건 불연속적(뚝뚝 끊김)으로 애니메이션이 작동합니다.
✅ 등록된 CSS 변수 (@property 사용)
@property --main-color {
syntax: "<color>"; /* 브라우저에게 "이건 '색상'이야!"라고 정체를 알려줌 */
inherits: false;
initial-value: red;
}
이렇게 @property를 사용해 "이 변수는 색상 데이터야!"라고 주민등록(등록)을 해주면, 브라우저가 드디어 중간값을 계산할 수 있게 되어 부드러운 색상 변환(보간)이 가능해집니다.