CSS Animation | Transition, Animation, and Transform
이 글의 핵심
CSS animations tutorial: transitions, transforms, and @keyframes—timing functions, GPU-friendly motion, will-change, reduced motion, and production patterns.
Introduction
Motion brings interfaces to life
CSS animation adds life and interactivity to the web. You can build smooth motion without JavaScript. Why animation matters:
- UX: natural state changes
- Feedback: responses to hover, tap, and focus
- Attention: highlight important UI
- Brand: distinctive motion design
- Performance: GPU-accelerated properties can hit 60fps Three pillars:
- Transition: interpolate between state A and B
- Transform: move, rotate, and scale
- Animation: complex timelines with
@keyframes
1. Transitions
Basic usage
A transition makes property changes smooth.
.box {
width: 100px;
height: 100px;
background: #3498db;
/* property | duration | timing | delay */
transition: all 0.3s ease 0s;
}
.box:hover {
width: 200px;
background: #2ecc71;
}
How it works:
State A (initial) State B (hover)
width: 100px → width: 200px
background: blue → background: green
The transition interpolates over 0.3s
Multiple properties
.box {
transition: width 0.3s ease,
background-color 0.5s linear,
transform 0.2s ease-out;
}
/* Or longhands */
.box {
transition-property: width, background-color;
transition-duration: 0.3s, 0.5s;
transition-timing-function: ease, linear;
transition-delay: 0s, 0.1s;
}
Timing functions
.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);
}
Visual sketch:
linear: ────────────
ease: ╱‾‾‾‾‾‾‾╲
ease-in: ╱─────────
ease-out: ─────────╲
ease-in-out: ╱‾‾‾‾‾‾╲
Live demo
<!DOCTYPE html>
<html lang="en">
<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">Color</div>
<div class="box box-2">Scale</div>
<div class="box box-3">Rotate</div>
<div class="box box-4">Bounce</div>
</div>
</body>
</html>
2. Transform
2D transforms
.box {
transform: translate(50px, 100px);
transform: translateX(50px);
transform: translateY(100px);
transform: scale(1.5);
transform: scale(2, 0.5);
transform: scaleX(2);
transform: scaleY(0.5);
transform: rotate(45deg);
transform: rotate(-90deg);
transform: skew(10deg, 20deg);
transform: skewX(10deg);
transform: skewY(20deg);
/* Order matters when combining */
transform: translate(50px, 50px) rotate(45deg) scale(1.5);
}
Order matters:
.box-1 {
transform: rotate(45deg) translate(100px, 0);
}
.box-2 {
transform: translate(100px, 0) rotate(45deg);
}
3D transforms
.box {
transform: translateZ(100px);
transform: translate3d(50px, 50px, 100px);
transform: rotateX(45deg);
transform: rotateY(45deg);
transform: rotateZ(45deg);
transform: rotate3d(1, 1, 1, 45deg);
transform: scaleZ(2);
transform: scale3d(1.5, 1.5, 2);
}
Perspective
.container {
perspective: 1000px;
perspective-origin: 50% 50%;
}
.box {
transform: perspective(1000px) rotateY(45deg);
}
Example markup (structure used throughout this tutorial):
<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
.box {
transform-origin: center center;
transform-origin: top left;
transform-origin: bottom right;
transform-origin: 50% 50%;
transform-origin: 0 0;
}
3. Animation (@keyframes)
Defining keyframes
@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);
}
}
Applying animations
.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 properties in depth
.box {
animation-iteration-count: 1;
animation-iteration-count: 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;
animation-play-state: running;
animation-play-state: paused;
}
Notification badge example
<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">
New message
</div>
4. More examples
Example 1: Button effects
<!DOCTYPE html>
<html lang="en">
<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;
}
.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);
}
.btn-scale {
transition: transform 0.3s ease;
}
.btn-scale:hover {
transform: scale(1.1);
}
.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%;
}
.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;
}
@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">Lift</button>
<button class="btn btn-scale">Scale</button>
<button class="btn btn-gradient">Gradient</button>
<button class="btn btn-border">Border fill</button>
<button class="btn btn-shake">Shake</button>
</div>
</body>
</html>
Example 2: Loading animations
Spinner, bouncing dots, and indeterminate progress bar reuse the CSS patterns listed in the sections above.
Example 3: Card flip
Use backface-visibility and rotateY; label faces Front and Back.
Example 4: Staggered fade-in
Classes fade-in-1 … fade-in-5 with increasing delays—label rows First block through Fifth block (scale).
Example 5: Infinite ambient motion
float, rotate, and pulse keyframes on three boxes—identical CSS to the original tutorial.
5. Performance
GPU-friendly properties
Fast (compositor-friendly):
.box {
/* ✅ Preferred: no layout thrash */
transform: translateX(100px);
transform: scale(1.5);
transform: rotate(45deg);
opacity: 0.5;
}
Slower (layout/paint):
.box {
width: 200px;
height: 200px;
left: 100px;
top: 100px;
margin: 20px;
padding: 20px;
}
Comparison
| Property | Layout | Paint | Composite | Cost |
|---|---|---|---|---|
transform | no | no | yes | low |
opacity | no | no | yes | low |
background-color | no | yes | no | medium |
width, height | yes | yes | yes | high |
left, top | yes | yes | yes | high |
will-change
.box {
will-change: transform, opacity;
}
Use sparingly—only on elements that will actually animate. Prefer toggling will-change from JavaScript around hover/animation lifecycle.
Forcing GPU layers
.box {
transform: translateZ(0);
}
6. Common issues
- Janky motion: animate
transform/opacityinstead of width/height/position when possible. - Animation on load: gate with a class or
animation-delayso content does not surprise users. - Snap back after animation: use
animation-fill-mode: forwards. - Unexpected transform results: remember multiplication order is right-to-left in screen space.
z-indexignored: give the elementpositionand a stacking context when combining withtransform.
7. Practical tips
- Reusable keyframes:
fadeIn,slideIn,bounce,shake,rotate. - ease-out feels natural for most UI exits; ~0.3s is a common transition length.
- Respect prefers-reduced-motion for accessibility.
- Chrome DevTools Animations panel helps inspect timelines.
8. Advanced
- Stack multiple animations on one element.
- Chain steps inside a single
@keyframesblock for multi-stage motion. - Drive animations from JavaScript with classes and
animation-play-state.
9. Project: interactive cards
Full markup uses English copy: product titles Product 1–3, sample prices in KRW (e.g. ₩29,000), buttons Buy, lang="en", title Interactive cards.
10. Browser support
| Feature | 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+ | — |
| Vendor prefixes for legacy WebKit/Gecko/Opera are shown in the original article; prefer autoprefixer in real projects. |
Summary
- Transition: interpolate between two states.
- Transform: geometric transforms, often cheap to animate.
- Animation:
@keyframesfor multi-step timelines. - Performance: favor
transformandopacity. - will-change: hint sparingly.
- Timing:
ease,ease-in-out,cubic-bezier. - fill-mode:
forwardskeeps the final keyframe.
Next steps
- JavaScript DOM APIs
- JS animation libraries
- React animation libraries
Related posts
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. CSS animations tutorial: transitions, transforms, and @keyframes—timing functions, GPU-friendly motion, will-change.
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
Keywords Covered in This Article (Related Search Terms)
This article covers CSS, Animation, Transition, Transform, Keyframes.