[2026] CSS 애니메이션 | Transition, Animation, Transform
이 글의 핵심
CSS 애니메이션: Transition, Animation, Transform. Transition (전환)·Transform (변형).
들어가며
”움직임으로 생명을 불어넣다”
CSS transition·animation은 상태 변화(호버, 로딩 등)를 GPU 친화적인 방식으로 보여 주기 좋습니다. 단순 피드백은 CSS만으로 처리하고, 복잡한 로직은 JavaScript와 나누는 식으로 쓰입니다. 애니메이션을 쓰면 좋은 경우:
- ✅ 사용자 경험: 자연스러운 전환
- ✅ 피드백: 클릭, 호버 등의 반응
- ✅ 주의 집중: 중요한 요소 강조
- ✅ 브랜드: 독특한 개성 표현
- ✅ 성능: GPU 가속으로 부드러운 60fps CSS 애니메이션 3요소:
- Transition: 상태 변화 (A → B)
- Transform: 변형 (이동, 회전, 크기)
- Animation: 복잡한 애니메이션 (@keyframes)
실무에서 마주한 현실
개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.
1. Transition (전환)
기본 사용
Transition은 CSS 속성이 부드럽게 변화하도록 합니다. 아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
width: 100px;
height: 100px;
background: #3498db;
/* 속성 | 시간 | 타이밍 함수 | 지연 */
transition: all 0.3s ease 0s;
}
.box:hover {
width: 200px;
background: #2ecc71;
}
동작 원리: 아래 코드는 text를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
상태 A (초기) 상태 B (hover)
width: 100px → width: 200px
background: blue → background: green
transition이 0.3초 동안 부드럽게 보간
개별 속성 지정
아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
/* 여러 속성 */
transition: width 0.3s ease,
background-color 0.5s linear,
transform 0.2s ease-out;
}
/* 또는 개별 지정 */
.box {
transition-property: width, background-color;
transition-duration: 0.3s, 0.5s;
transition-timing-function: ease, linear;
transition-delay: 0s, 0.1s;
}
타이밍 함수 (Timing Function)
아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
/* 기본 함수 */
transition-timing-function: linear; /* 일정한 속도 */
transition-timing-function: ease; /* 천천히-빠르게-천천히 (기본값) */
transition-timing-function: ease-in; /* 천천히 시작 */
transition-timing-function: ease-out; /* 천천히 끝 */
transition-timing-function: ease-in-out; /* 천천히 시작과 끝 */
/* 커스텀 베지어 곡선 */
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
/* 단계 함수 */
transition-timing-function: steps(4, end);
}
시각적 비교: 아래 코드는 text를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
linear: ────────────
ease: ╱‾‾‾‾‾‾‾╲
ease-in: ╱─────────
ease-out: ─────────╲
ease-in-out: ╱‾‾‾‾‾‾╲
실전 예제
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<style>
.demo-container {
display: flex;
gap: 20px;
padding: 20px;
flex-wrap: wrap;
}
.box {
width: 100px;
height: 100px;
background: #3498db;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
cursor: pointer;
}
.box-1 {
transition: background 0.3s ease;
}
.box-1:hover {
background: #e74c3c;
}
.box-2 {
transition: transform 0.3s ease;
}
.box-2:hover {
transform: scale(1.2);
}
.box-3 {
transition: all 0.3s ease;
}
.box-3:hover {
transform: rotate(45deg);
background: #2ecc71;
}
.box-4 {
transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.box-4:hover {
transform: scale(1.3) rotate(10deg);
}
</style>
</head>
<body>
<div class="demo-container">
<div class="box box-1">색상</div>
<div class="box box-2">크기</div>
<div class="box box-3">회전</div>
<div class="box box-4">바운스</div>
</div>
</body>
</html>
2. Transform (변형)
2D Transform
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
/* 이동 (translate) */
transform: translate(50px, 100px); /* x, y */
transform: translateX(50px); /* x만 */
transform: translateY(100px); /* y만 */
/* 크기 조절 (scale) */
transform: scale(1.5); /* 1.5배 */
transform: scale(2, 0.5); /* x 2배, y 0.5배 */
transform: scaleX(2); /* x만 */
transform: scaleY(0.5); /* y만 */
/* 회전 (rotate) */
transform: rotate(45deg); /* 45도 회전 */
transform: rotate(-90deg); /* -90도 회전 */
/* 기울이기 (skew) */
transform: skew(10deg, 20deg); /* x, y */
transform: skewX(10deg); /* x만 */
transform: skewY(20deg); /* y만 */
/* 여러 개 조합 (순서 중요!) */
transform: translate(50px, 50px) rotate(45deg) scale(1.5);
}
조합 순서의 중요성: 아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* 다른 결과 */
.box-1 {
transform: rotate(45deg) translate(100px, 0);
/* 회전 후 이동 → 대각선 이동 */
}
.box-2 {
transform: translate(100px, 0) rotate(45deg);
/* 이동 후 회전 → 오른쪽 이동 + 회전 */
}
3D Transform
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
/* 3D 이동 */
transform: translateZ(100px); /* z축 */
transform: translate3d(50px, 50px, 100px); /* x, y, z */
/* 3D 회전 */
transform: rotateX(45deg); /* x축 회전 */
transform: rotateY(45deg); /* y축 회전 */
transform: rotateZ(45deg); /* z축 회전 (= rotate) */
transform: rotate3d(1, 1, 1, 45deg); /* 벡터 기준 회전 */
/* 3D 크기 조절 */
transform: scaleZ(2);
transform: scale3d(1.5, 1.5, 2);
}
Perspective (원근감)
아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* 부모에 적용 */
.container {
perspective: 1000px; /* 원근 거리 */
perspective-origin: 50% 50%; /* 시점 */
}
/* 또는 자식에 적용 */
.box {
transform: perspective(1000px) rotateY(45deg);
}
예제: 다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
.perspective-demo {
display: flex;
gap: 50px;
padding: 50px;
}
.container {
perspective: 1000px;
width: 200px;
height: 200px;
}
.box {
width: 100%;
height: 100%;
background: #3498db;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
transition: transform 0.6s;
}
.container:hover .box {
transform: rotateY(180deg);
}
.container-1 { perspective: 500px; } /* 가까움 */
.container-2 { perspective: 1000px; } /* 중간 */
.container-3 { perspective: 2000px; } /* 멀음 */
</style>
<div class="perspective-demo">
<div class="container container-1">
<div class="box">500px</div>
</div>
<div class="container container-2">
<div class="box">1000px</div>
</div>
<div class="container container-3">
<div class="box">2000px</div>
</div>
</div>
Transform Origin (기준점)
아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
/* 기준점 변경 */
transform-origin: center center; /* 기본값 */
transform-origin: top left; /* 왼쪽 위 */
transform-origin: bottom right; /* 오른쪽 아래 */
transform-origin: 50% 50%; /* 퍼센트 */
transform-origin: 0 0; /* 픽셀 */
}
예제: 다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
.origin-demo {
display: flex;
gap: 50px;
padding: 50px;
}
.box {
width: 100px;
height: 100px;
background: #3498db;
transition: transform 0.3s;
}
.box-1 {
transform-origin: center;
}
.box-1:hover {
transform: rotate(45deg); /* 중심 기준 */
}
.box-2 {
transform-origin: top left;
}
.box-2:hover {
transform: rotate(45deg); /* 왼쪽 위 기준 */
}
.box-3 {
transform-origin: bottom right;
}
.box-3:hover {
transform: rotate(45deg); /* 오른쪽 아래 기준 */
}
</style>
<div class="origin-demo">
<div class="box box-1"></div>
<div class="box box-2"></div>
<div class="box box-3"></div>
</div>
3. Animation (@keyframes)
Keyframes 정의
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* from-to 형식 */
@keyframes slide {
from {
transform: translateX(0);
opacity: 0;
}
to {
transform: translateX(300px);
opacity: 1;
}
}
/* 퍼센트 형식 (더 유연) */
@keyframes bounce {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-100px);
}
100% {
transform: translateY(0);
}
}
/* 복잡한 애니메이션 */
@keyframes complex {
0% {
transform: translateX(0) rotate(0deg);
background: #3498db;
}
25% {
transform: translateX(100px) rotate(90deg);
background: #2ecc71;
}
50% {
transform: translateX(200px) rotate(180deg);
background: #e74c3c;
}
75% {
transform: translateX(100px) rotate(270deg);
background: #f39c12;
}
100% {
transform: translateX(0) rotate(360deg);
background: #3498db;
}
}
Animation 적용
아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
/* 개별 속성 */
animation-name: slide; /* 애니메이션 이름 */
animation-duration: 2s; /* 지속 시간 */
animation-timing-function: ease-in-out; /* 타이밍 함수 */
animation-delay: 0s; /* 지연 시간 */
animation-iteration-count: infinite; /* 반복 횟수 */
animation-direction: alternate; /* 방향 */
animation-fill-mode: forwards; /* 채우기 모드 */
animation-play-state: running; /* 재생 상태 */
/* 축약형 (권장) */
animation: slide 2s ease-in-out 0s infinite alternate forwards;
}
Animation 속성 상세
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
/* 반복 횟수 */
animation-iteration-count: 1; /* 1번 */
animation-iteration-count: 3; /* 3번 */
animation-iteration-count: infinite; /* 무한 */
/* 방향 */
animation-direction: normal; /* 정방향 (기본값) */
animation-direction: reverse; /* 역방향 */
animation-direction: alternate; /* 정방향-역방향 반복 */
animation-direction: alternate-reverse;/* 역방향-정방향 반복 */
/* 채우기 모드 */
animation-fill-mode: none; /* 기본값, 원래 상태 */
animation-fill-mode: forwards; /* 마지막 상태 유지 */
animation-fill-mode: backwards; /* 첫 상태로 시작 */
animation-fill-mode: both; /* forwards + backwards */
/* 재생 상태 */
animation-play-state: running; /* 재생 (기본값) */
animation-play-state: paused; /* 일시정지 */
}
실전 예제
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.1);
opacity: 0.8;
}
}
.notification {
position: relative;
display: inline-block;
padding: 10px 20px;
background: #3498db;
color: white;
border-radius: 5px;
}
.notification::after {
content: ';
position: absolute;
top: -5px;
right: -5px;
width: 20px;
height: 20px;
background: #e74c3c;
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
}
</style>
<div class="notification">
새 메시지
</div>
4. 실전 예제
예제 1: 버튼 효과 모음
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<style>
.button-demo {
display: flex;
gap: 20px;
padding: 50px;
flex-wrap: wrap;
}
.btn {
padding: 15px 30px;
background: #3498db;
color: white;
border: none;
border-radius: 5px;
font-size: 1rem;
cursor: pointer;
text-decoration: none;
display: inline-block;
}
/* 1. 호버 리프트 */
.btn-lift {
transition: all 0.3s ease;
}
.btn-lift:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.btn-lift:active {
transform: translateY(-2px);
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
}
/* 2. 확대 */
.btn-scale {
transition: transform 0.3s ease;
}
.btn-scale:hover {
transform: scale(1.1);
}
/* 3. 그라데이션 이동 */
.btn-gradient {
background: linear-gradient(90deg, #3498db, #2ecc71);
background-size: 200% 100%;
background-position: 0% 0%;
transition: background-position 0.5s ease;
}
.btn-gradient:hover {
background-position: 100% 0%;
}
/* 4. 테두리 애니메이션 */
.btn-border {
position: relative;
overflow: hidden;
transition: color 0.3s ease;
}
.btn-border::before {
content: ';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: #2ecc71;
transition: left 0.3s ease;
z-index: -1;
}
.btn-border:hover {
color: white;
}
.btn-border:hover::before {
left: 0;
}
/* 5. 흔들기 */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-10px); }
75% { transform: translateX(10px); }
}
.btn-shake:hover {
animation: shake 0.3s ease;
}
</style>
</head>
<body>
<div class="button-demo">
<button class="btn btn-lift">리프트</button>
<button class="btn btn-scale">확대</button>
<button class="btn btn-gradient">그라데이션</button>
<button class="btn btn-border">테두리</button>
<button class="btn btn-shake">흔들기</button>
</div>
</body>
</html>
예제 2: 로딩 애니메이션
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
/* 스피너 */
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* 점 3개 */
@keyframes bounce {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
.dots {
display: flex;
gap: 10px;
}
.dot {
width: 15px;
height: 15px;
background: #3498db;
border-radius: 50%;
animation: bounce 1.4s infinite ease-in-out;
}
.dot:nth-child(1) { animation-delay: -0.32s; }
.dot:nth-child(2) { animation-delay: -0.16s; }
.dot:nth-child(3) { animation-delay: 0s; }
/* 바 */
@keyframes progress {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(400%);
}
}
.progress-bar {
width: 200px;
height: 4px;
background: #ecf0f1;
border-radius: 2px;
overflow: hidden;
}
.progress-bar::after {
content: ';
display: block;
width: 20%;
height: 100%;
background: #3498db;
animation: progress 1.5s ease-in-out infinite;
}
</style>
<div style="display: flex; gap: 50px; padding: 50px;">
<div class="spinner"></div>
<div class="dots">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<div class="progress-bar"></div>
</div>
예제 3: 카드 플립
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
.flip-container {
perspective: 1000px;
width: 300px;
height: 200px;
}
.flip-card {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
}
.flip-container:hover .flip-card {
transform: rotateY(180deg);
}
.flip-front, .flip-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
font-size: 1.5rem;
font-weight: bold;
}
.flip-front {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
}
.flip-back {
background: linear-gradient(135deg, #f093fb, #f5576c);
color: white;
transform: rotateY(180deg);
}
</style>
<div class="flip-container">
<div class="flip-card">
<div class="flip-front">앞면</div>
<div class="flip-back">뒷면</div>
</div>
</div>
예제 4: 페이드 인 애니메이션
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInLeft {
from {
opacity: 0;
transform: translateX(-50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeInScale {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
.animate-on-scroll {
animation: fadeIn 1s ease-out;
}
.fade-in-1 { animation: fadeIn 1s ease-out 0s both; }
.fade-in-2 { animation: fadeIn 1s ease-out 0.2s both; }
.fade-in-3 { animation: fadeIn 1s ease-out 0.4s both; }
.fade-in-4 { animation: fadeInLeft 1s ease-out 0.6s both; }
.fade-in-5 { animation: fadeInScale 1s ease-out 0.8s both; }
.content-box {
padding: 20px;
margin: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
</style>
<div class="content-box fade-in-1">첫 번째 요소</div>
<div class="content-box fade-in-2">두 번째 요소</div>
<div class="content-box fade-in-3">세 번째 요소</div>
<div class="content-box fade-in-4">네 번째 요소 (왼쪽에서)</div>
<div class="content-box fade-in-5">다섯 번째 요소 (확대)</div>
예제 5: 무한 애니메이션
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
}
.float-box {
width: 100px;
height: 100px;
background: #3498db;
border-radius: 10px;
animation: float 3s ease-in-out infinite;
}
.rotate-box {
width: 100px;
height: 100px;
background: #e74c3c;
animation: rotate 4s linear infinite;
}
.pulse-box {
width: 100px;
height: 100px;
background: #2ecc71;
border-radius: 50%;
animation: pulse 2s ease-in-out infinite;
}
</style>
<div style="display: flex; gap: 50px; padding: 50px;">
<div class="float-box"></div>
<div class="rotate-box"></div>
<div class="pulse-box"></div>
</div>
5. 성능 최적화
GPU 가속 속성
빠른 속성 (GPU 가속): 아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
/* ✅ 권장: 레이아웃에 영향 없음 */
transform: translateX(100px);
transform: scale(1.5);
transform: rotate(45deg);
opacity: 0.5;
}
느린 속성 (레이아웃 변경): 아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 실행 예제
.box {
/* ❌ 비권장: 레이아웃 재계산 */
width: 200px;
height: 200px;
left: 100px;
top: 100px;
margin: 20px;
padding: 20px;
}
성능 비교
| 속성 | 레이아웃 | 페인트 | 합성 | 성능 |
|---|---|---|---|---|
transform | ❌ | ❌ | ✅ | 빠름 |
opacity | ❌ | ❌ | ✅ | 빠름 |
background-color | ❌ | ✅ | ❌ | 보통 |
width, height | ✅ | ✅ | ✅ | 느림 |
left, top | ✅ | ✅ | ✅ | 느림 |
will-change
애니메이션 전에 브라우저에 미리 알립니다: 아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
/* 애니메이션 전 최적화 힌트 */
will-change: transform, opacity;
}
.box:hover {
transform: scale(1.2);
opacity: 0.8;
}
주의사항: 다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* ❌ 나쁨: 모든 요소에 적용 */
* {
will-change: transform; /* 메모리 낭비 */
}
/* ✅ 좋음: 필요한 요소만 */
.animated-element {
will-change: transform;
}
/* ✅ 더 좋음: JavaScript로 동적 추가/제거 */
element.addEventListener('mouseenter', () => {
element.style.willChange = 'transform';
});
element.addEventListener('animationend', () => {
element.style.willChange = 'auto';
});
transform3d 강제 GPU 가속
다음은 간단한 css 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
/* 2D transform도 GPU 가속 */
transform: translateZ(0); /* 또는 translate3d(0, 0, 0) */
}
6. 자주 발생하는 문제
1. 애니메이션이 끊김
문제: 60fps를 유지하지 못함 해결: 다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* ❌ 나쁨 */
.box {
transition: width 0.3s; /* 레이아웃 재계산 */
}
.box:hover {
width: 200px;
}
/* ✅ 좋음 */
.box {
transition: transform 0.3s; /* GPU 가속 */
}
.box:hover {
transform: scaleX(2);
}
2. 애니메이션이 즉시 시작됨
문제: 페이지 로드 시 애니메이션이 바로 실행 해결: 아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
/* ❌ 나쁨 */
.box {
animation: slide 2s ease-in-out infinite;
}
/* ✅ 좋음: 클래스로 제어 */
.box.animate {
animation: slide 2s ease-in-out infinite;
}
다음은 간단한 javascript 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// JavaScript로 클래스 추가
setTimeout(() => {
document.querySelector('.box').classList.add('animate');
}, 100);
3. 애니메이션 후 원래 상태로 돌아감
문제: 애니메이션 종료 후 초기 상태로 복귀 해결: 다음은 간단한 css 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
animation: slide 2s ease-in-out forwards;
/* ↑ 마지막 상태 유지 */
}
4. transform 조합 순서
문제: 예상과 다른 결과 다음은 간단한 css 코드 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
/* 다른 결과 */
transform: rotate(45deg) translate(100px, 0);
/* vs */
transform: translate(100px, 0) rotate(45deg);
해결: 순서를 이해하고 의도에 맞게 작성
5. z-index가 작동하지 않음
문제: transform 사용 시 z-index 무시 해결: 아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
position: relative; /* 또는 absolute */
z-index: 10;
transform: translateX(50px);
}
7. 실전 팁
1. 자주 사용하는 애니메이션
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* 페이드 인 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* 슬라이드 인 */
@keyframes slideIn {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
/* 바운스 */
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-30px);
}
60% {
transform: translateY(-15px);
}
}
/* 흔들기 */
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
20%, 40%, 60%, 80% { transform: translateX(10px); }
}
/* 회전 */
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
2. 타이밍 함수 선택
아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
/* 자연스러운 움직임 */
.natural { transition: all 0.3s ease-out; }
/* 바운스 효과 */
.bounce { transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); }
/* 부드러운 시작 */
.smooth { transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
3. 반응형 애니메이션
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* 데스크톱: 애니메이션 활성화 */
.box {
transition: transform 0.3s ease;
}
/* 모바일: 애니메이션 비활성화 (성능) */
@media (max-width: 768px) {
.box {
transition: none;
}
}
/* 사용자 설정 존중 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
4. 디버깅
아래 코드는 css를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
/* 애니메이션 느리게 */
.box {
animation: slide 10s ease-in-out infinite;
/* ↑ 10초로 느리게 */
}
/* 일시정지 */
.box {
animation-play-state: paused;
}
Chrome DevTools:
- Elements 패널
- Animations 탭
- 애니메이션 타임라인 확인
8. 고급 기법
1. 다중 애니메이션
아래 코드는 css를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
.box {
animation:
slide 2s ease-in-out infinite,
rotate 3s linear infinite,
pulse 1s ease-in-out infinite;
}
2. 애니메이션 체이닝
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
@keyframes sequence {
0% {
transform: translateX(0);
background: #3498db;
}
33% {
transform: translateX(100px);
background: #2ecc71;
}
66% {
transform: translateX(100px) translateY(100px);
background: #e74c3c;
}
100% {
transform: translateX(0) translateY(0);
background: #3498db;
}
}
.box {
animation: sequence 3s ease-in-out infinite;
}
3. JavaScript 제어
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<style>
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(300px); }
}
.box {
width: 100px;
height: 100px;
background: #3498db;
}
.box.animate {
animation: slide 1s ease-in-out forwards;
}
</style>
<div class="box" id="box"></div>
<button id="startBtn">시작</button>
<button id="pauseBtn">일시정지</button>
<button id="resetBtn">리셋</button>
<script>
const box = document.getElementById('box');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resetBtn = document.getElementById('resetBtn');
startBtn.addEventListener('click', () => {
box.classList.add('animate');
box.style.animationPlayState = 'running';
});
pauseBtn.addEventListener('click', () => {
box.style.animationPlayState = 'paused';
});
resetBtn.addEventListener('click', () => {
box.classList.remove('animate');
void box.offsetWidth; /* 리플로우 강제 */
box.classList.add('animate');
});
box.addEventListener('animationend', () => {
console.log('애니메이션 완료');
});
</script>
9. 실전 프로젝트
프로젝트: 인터랙티브 카드
다음은 html를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>인터랙티브 카드</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #667eea, #764ba2);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
max-width: 1200px;
}
.card {
background: white;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
}
.card-image {
width: 100%;
height: 200px;
background: linear-gradient(135deg, #667eea, #764ba2);
position: relative;
overflow: hidden;
}
.card-image::before {
content: ';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
45deg,
transparent,
rgba(255,255,255,0.3),
transparent
);
transform: translateX(-100%);
transition: transform 0.6s;
}
.card:hover .card-image::before {
transform: translateX(100%);
}
.card-content {
padding: 25px;
}
.card h3 {
margin: 0 0 10px 0;
color: #2c3e50;
font-size: 1.5rem;
}
.card p {
margin: 0 0 20px 0;
color: #7f8c8d;
line-height: 1.6;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.price {
font-size: 1.8rem;
font-weight: bold;
color: #3498db;
}
.btn {
padding: 10px 20px;
background: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.btn::before {
content: ';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255,255,255,0.3);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:hover::before {
width: 300px;
height: 300px;
}
.btn:hover {
background: #2980b9;
transform: scale(1.05);
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: fadeInUp 0.6s ease-out;
}
.card:nth-child(1) { animation-delay: 0s; }
.card:nth-child(2) { animation-delay: 0.1s; }
.card:nth-child(3) { animation-delay: 0.2s; }
</style>
</head>
<body>
<div class="card-grid">
<div class="card">
<div class="card-image"></div>
<div class="card-content">
<h3>상품 1</h3>
<p>멋진 상품입니다. 지금 구매하세요!</p>
<div class="card-footer">
<span class="price">29,000원</span>
<button class="btn">구매</button>
</div>
</div>
</div>
<div class="card">
<div class="card-image"></div>
<div class="card-content">
<h3>상품 2</h3>
<p>최고의 품질을 자랑합니다.</p>
<div class="card-footer">
<span class="price">39,000원</span>
<button class="btn">구매</button>
</div>
</div>
</div>
<div class="card">
<div class="card-image"></div>
<div class="card-content">
<h3>상품 3</h3>
<p>특별한 할인 중입니다.</p>
<div class="card-footer">
<span class="price">49,000원</span>
<button class="btn">구매</button>
</div>
</div>
</div>
</div>
</body>
</html>
10. 브라우저 지원
지원 현황
| 속성 | Chrome | Firefox | Safari | Edge | IE |
|---|---|---|---|---|---|
transition | 26+ | 16+ | 9+ | 12+ | 10+ |
transform | 36+ | 16+ | 9+ | 12+ | 10+ |
animation | 43+ | 16+ | 9+ | 12+ | 10+ |
will-change | 36+ | 36+ | 9.1+ | 79+ | ❌ |
벤더 프리픽스 (구형 브라우저)
다음은 css를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
.box {
-webkit-transition: all 0.3s ease; /* Safari, Chrome */
-moz-transition: all 0.3s ease; /* Firefox */
-o-transition: all 0.3s ease; /* Opera */
transition: all 0.3s ease; /* 표준 */
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
@-webkit-keyframes slide {
from { -webkit-transform: translateX(0); }
to { -webkit-transform: translateX(300px); }
}
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(300px); }
}
정리
핵심 요약
- Transition: A→B 상태 변화 애니메이션
- Transform: 이동, 회전, 크기, 기울이기
- Animation: @keyframes로 복잡한 애니메이션
- 성능: transform, opacity만 사용 (GPU 가속)
- will-change: 애니메이션 최적화 힌트
- 타이밍 함수: ease, ease-in-out, cubic-bezier
- fill-mode: forwards로 마지막 상태 유지
애니메이션 속성 비교
| 속성 | 용도 | 트리거 | 반복 | 복잡도 |
|---|---|---|---|---|
transition | 상태 변화 | hover, focus 등 | 1회 | 간단 |
animation | 복잡한 애니메이션 | 자동 또는 클래스 | 설정 가능 | 복잡 |
성능 최적화 체크리스트
- ✅
transform,opacity만 사용 - ✅
will-change로 최적화 힌트 - ✅
transform3d(0,0,0)로 GPU 가속 강제 - ✅ 60fps 유지 (16.67ms/프레임)
- ✅
prefers-reduced-motion존중 - ❌
width,height,left,top애니메이션 피하기 - ❌ 모든 요소에
will-change적용 금지
실전 팁
- ease-out: 대부분의 경우 자연스러움
- 0.3s: 일반적인 transition 시간
- forwards: 애니메이션 마지막 상태 유지
- transform 조합: 순서 중요
- GPU 가속: transform, opacity 사용
- JavaScript 제어: 클래스 추가/제거
- 반응형: 모바일에서 애니메이션 줄이기
- 접근성: prefers-reduced-motion 존중
다음 단계
- JavaScript DOM 조작
- JavaScript 애니메이션 라이브러리
- React 애니메이션