HTML & CSS · Lesson 12 of 13
Transitions, Transforms and Animations
Add motion with CSS transitions, transforms and @keyframes animations: timing functions, smooth performance, loaders and prefers-reduced-motion.
- Intermediate
- 16 min read
- 4 objectives
Before this lessonLesson 11: Grid and Responsive Design
What you will learn
- Animate state changes with transition and timing functions
- Move, scale and rotate elements with transform
- Write @keyframes animations such as spinners and fade-ins
- Keep motion smooth and respect prefers-reduced-motion
Your Progress
0 of 13 lessons 0%
- Lessons0 / 13
- Completed0
- Est. time left~ 4 hours
Create a free account to keep your progress on every device.
Tip: pressing Next marks this lesson complete automatically.
Motion, used lightly, makes an interface feel responsive: a button that eases into its hover colour, a menu that slides in, a skeleton loader that pulses while data arrives. It helps users see what changed. Used carelessly, it slows people down and can make some users physically ill. CSS gives you three tools: transitions for moving between two states, transforms for moving and resizing things cheaply, and keyframe animations for anything more complex.
Transitions
A transition smoothly animates a property when its value changes, for example on hover or when a class is added with JavaScript. You put the transition on the base state, not the hover state, so it animates both in and out.
.button {
background: #2563eb;
transition: background-color 200ms ease, box-shadow 200ms ease;
}
.button:hover {
background: #1d4ed8;
box-shadow: 0 4px 12px rgb(37 99 235 / 35%);
}
/* Longhand, for reference */
.panel {
transition-property: opacity;
transition-duration: 300ms;
transition-timing-function: ease-out;
transition-delay: 0ms;
}Timing functions
The timing function controls acceleration. Real objects do not move at a constant speed, so linear motion looks robotic.
ease(default): quick start, gentle end. Fine for most things.ease-out: fast then slow. Best for elements entering the screen.ease-in: slow then fast. Best for elements leaving.linear: constant speed. Use for spinners and progress bars.cubic-bezier(0.34, 1.56, 0.64, 1): custom curves, like this slight overshoot "bounce".
Keep UI transitions short: roughly 150-300ms. Anything over 500ms starts to feel sluggish.
Transforms
transform changes how an element is drawn without affecting layout. Neighbours do not move, and the browser can hand the work to the GPU, which is why transforms animate so smoothly.
.lift:hover { transform: translateY(-4px); }
.grow:hover { transform: scale(1.05); }
.spin { transform: rotate(45deg); }
.combo { transform: translateX(20px) rotate(10deg) scale(0.9); } /* applied right to left */
/* Individual transform properties: easier to combine and animate separately */
.card {
translate: 0 0;
scale: 1;
transition: translate 200ms ease-out, scale 200ms ease-out;
}
.card:hover { translate: 0 -4px; scale: 1.02; }
/* Rotate around a corner instead of the centre */
.flag { transform-origin: top left; }A classic trick: translate(-50%, -50%) with top: 50%; left: 50% centres an absolutely positioned element, because percentages in translate refer to the element's own size.
Keyframe animations
When you need more than two states, or motion that runs on its own without a hover, define an animation with @keyframes and attach it with the animation property.
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 32px;
height: 32px;
border: 3px solid #e2e8f0;
border-top-color: #2563eb;
border-radius: 50%;
animation: spin 800ms linear infinite;
}
@keyframes fade-up {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.toast {
animation: fade-up 300ms ease-out both;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.skeleton { background: #e2e8f0; animation: pulse 1.5s ease-in-out infinite; }The animation shorthand takes: name, duration, timing function, delay, iteration count, direction and fill mode. both as the fill mode applies the first keyframe during any delay and keeps the last keyframe when it finishes, so the element does not snap back.
/* Staggered entrance using a custom property per item */
.list-item {
animation: fade-up 400ms ease-out both;
animation-delay: calc(var(--i) * 60ms);
}
/* In HTML: <li class="list-item" style="--i: 0">, --i: 1, --i: 2 ... */Performance: animate the cheap properties
Browsers draw a frame in stages: layout (work out sizes and positions), paint (fill in pixels) and composite (stack the layers). Animating width, height, top or margin triggers layout on every frame, which can stutter on phones. Animating transform and opacity only needs compositing, which is very cheap.
/* Janky: forces layout 60 times a second */
.drawer { left: -300px; transition: left 300ms; }
.drawer.open { left: 0; }
/* Smooth: compositor only */
.drawer { transform: translateX(-100%); transition: transform 300ms ease-out; }
.drawer.open { transform: translateX(0); }will-change: transform hints that an element is about to animate. Apply it sparingly, only to elements that genuinely animate, because each one uses extra memory.
Respect reduced motion
People with vestibular disorders can get dizziness or nausea from large movement, parallax and zooming. Operating systems have a "reduce motion" setting, and CSS can read it. Keep functional feedback like colour changes, but remove or shorten big motion.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}Recap
- Put
transitionon the base state and list specific properties; keep durations around 150-300ms. - Use
ease-outfor entering,ease-infor leaving andlinearfor continuous spinning. transform(ortranslate,scale,rotate) moves elements without affecting layout.- Use
@keyframeswithanimationfor loaders and entrances;bothfill mode prevents snapping. - Animate only
transformandopacityfor smoothness, and honourprefers-reduced-motion.
// Write your solution here
Finished reading? Mark this lesson complete to track your progress.
