|$ curl https://forge-ai.dev/api/markdown?path=docs/css/animations
$cat docs/css-animations-&-transitions.md
updated Recently·28 min read·published

CSS Animations & Transitions

CSSAnimationsAdvancedAdvanced
Introduction

CSS animations and transitions bring interfaces to life. While both create motion, they serve different purposes: transitions interpolate between two states (start → end), while animations support multi-step sequences with自主 control over timing, iteration, and direction.

Performance is critical for smooth animations. The browser rendering pipeline has three key stages: Layout, Paint, and Composite. Animating transform and opacity only triggers compositing — the cheapest stage — while animating width, height, or top/left triggers expensive Layout recalculations on every frame.

animations-intro.css
CSS
1/* Transition: smooth state change on hover */
2.button {
3 background: #1A1A2E;
4 transform: scale(1);
5 transition: transform 0.2s ease, background 0.2s ease;
6}
7
8.button:hover {
9 background: #00FF41;
10 transform: scale(1.05);
11}
12
13/* Animation: multi-step sequence */
14@keyframes pulse {
15 0% { transform: scale(1); opacity: 1; }
16 50% { transform: scale(1.1); opacity: 0.8; }
17 100% { transform: scale(1); opacity: 1; }
18}
19
20.pulse {
21 animation: pulse 2s ease-in-out infinite;
22}
preview
Transitions

CSS transitions interpolate between property values when a state change occurs (e.g., :hover, class toggle, JS-driven changes). A transition requires four sub-properties defining what, how long, what timing, and when to start.

Transition Sub-Properties

transitions.css
CSS
1.element {
2 /* Which property to transition */
3 transition-property: transform, opacity, background;
4
5 /* Duration of the transition */
6 transition-duration: 0.3s, 0.2s, 0.3s;
7
8 /* Timing function: how the intermediate values are calculated */
9 transition-timing-function: ease, linear, ease-out;
10
11 /* Delay before the transition starts */
12 transition-delay: 0s, 0.1s, 0s;
13
14 /* Shorthand (order: property | duration | timing | delay) */
15 transition: transform 0.3s ease 0s,
16 opacity 0.2s linear 0.1s,
17 background 0.3s ease-out 0s;
18}
19
20/* Single shorthand — applies to all */
21.all {
22 transition: all 0.25s ease;
23}
24
25/* Avoid "all" for performance — be explicit */
26.better {
27 transition: transform 0.25s ease, opacity 0.25s ease;
28}

Transition on Interaction

card-transition.css
CSS
1.card {
2 background: #0D0D0D;
3 border: 1px solid #222222;
4 transform: translateY(0);
5 transition:
6 transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
7 box-shadow 0.3s ease,
8 border-color 0.3s ease;
9}
10
11.card:hover {
12 transform: translateY(-4px);
13 box-shadow: 0 12px 24px rgba(0, 0, 0, 0.4);
14 border-color: #00FF41;
15}
16
17/* Reverse transition is often faster (good UX) */
18.card {
19 transition:
20 transform 0.25s ease,
21 box-shadow 0.25s ease;
22}
23
24.card:hover {
25 transition:
26 transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
27 box-shadow 0.2s ease;
28}
preview
Timing Functions

Timing functions (easing curves) define the rate of change during an animation or transition. The choice of easing curve dramatically affects how motion feels — whether mechanical and robotic or natural and polished.

Functioncubic-bezier EquivalentCharacterBest For
easecubic-bezier(0.25, 0.1, 0.25, 1)Fast start, slow endDefault — general purpose
linearcubic-bezier(0, 0, 1, 1)Constant speedColor changes, progress bars, spinners
ease-incubic-bezier(0.42, 0, 1, 1)Slow start, fast endObjects leaving (fade out, slide out)
ease-outcubic-bezier(0, 0, 0.58, 1)Fast start, slow endObjects entering (fade in, slide in)
ease-in-outcubic-bezier(0.42, 0, 0.58, 1)Slow start and endAccordion, reversible transitions

Custom cubic-bezier()

timing-functions.css
CSS
1/* Custom easing curves */
2.bounce-in {
3 transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
4 /* Overshoots then settles — like a spring */
5}
6
7.smooth-out {
8 transition: opacity 0.3s cubic-bezier(0.215, 0.61, 0.355, 1);
9 /* Smooth deceleration — "ease out quint" */
10}
11
12.snappy {
13 transition: transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
14 /* Quick, responsive feel — good for micro-interactions */
15}
16
17/* steps() — discrete jumps */
18.step-anim {
19 animation: loader 1s steps(4) infinite;
20}
21
22@keyframes loader {
23 0% { transform: translateX(0); }
24 100% { transform: translateX(80px); }
25}
26
27/* Useful steps() functions */
28.typing { animation: type 2s steps(30) forwards; }
29.frame { animation: sprite 0.8s steps(8) infinite; }
preview
Animations & @keyframes

CSS animations use @keyframes to define multi-step sequences with fine-grained control over timing, repetition, direction, and fill behavior.

@keyframes Syntax

keyframes.css
CSS
1/* Named keyframes — define the animation sequence */
2@keyframes fadeInUp {
3 from {
4 opacity: 0;
5 transform: translateY(20px);
6 }
7 to {
8 opacity: 1;
9 transform: translateY(0);
10 }
11}
12
13/* Percentage keyframes — more than two steps */
14@keyframes slideIn {
15 0% { transform: translateX(-100%); opacity: 0; }
16 60% { transform: translateX(10%); opacity: 1; }
17 80% { transform: translateX(-5%); }
18 100% { transform: translateX(0); }
19}
20
21/* Applying the animation */
22.element {
23 animation-name: fadeInUp;
24 animation-duration: 0.6s;
25 animation-timing-function: ease-out;
26 animation-delay: 0s;
27 animation-iteration-count: 1;
28 animation-direction: normal;
29 animation-fill-mode: both;
30 animation-play-state: running;
31}
32
33/* Shorthand */
34.element {
35 animation: fadeInUp 0.6s ease-out both;
36}

Animation Sub-Properties Reference

PropertyDescriptionValues
animation-nameName of the @keyframes rule<keyframes-name> | none
animation-durationHow long one cycle takes0.3s | 500ms
animation-timing-functionEasing curve for the animationease | linear | cubic-bezier() | steps()
animation-delayDelay before starting0s | -0.5s (starts mid-way)
animation-iteration-countNumber of cycles1 | 3 | infinite
animation-directionDirection of the cyclenormal | reverse | alternate | alternate-reverse
animation-fill-modeStyles before/after the animationnone | forwards | backwards | both
animation-play-statePause or resumerunning | paused

Animation Direction & Fill Mode

animation-direction-fill.css
CSS
1/* Fill mode — controls element state before and after */
2.fade-in {
3 animation: fadeIn 0.5s ease-out both;
4 /* "both" = backwards (initial state before delay) + forwards (stay at end) */
5}
6
7.pulse-loop {
8 animation: pulse 2s ease-in-out infinite alternate;
9 /* alternates direction every cycle */
10}
11
12/* Negative delay — starts mid-animation */
13.staggered {
14 animation: slideUp 0.6s ease both;
15}
16
17.staggered:nth-child(1) { animation-delay: 0s; }
18.staggered:nth-child(2) { animation-delay: 0.1s; }
19.staggered:nth-child(3) { animation-delay: 0.2s; }
20.staggered:nth-child(4) { animation-delay: 0.3s; }
21.staggered:nth-child(5) { animation-delay: 0.4s; }
22
23/* Pause on hover */
24.container:hover .animated-item {
25 animation-play-state: paused;
26}
preview
Transform

The transform property modifies the coordinate space of an element, enabling translation, rotation, scaling, and skewing. Multiple transform functions can be chained in a single declaration.

2D Transform Functions

transform-2d.css
CSS
1/* Translate — move the element */
2.translate { transform: translateX(20px); }
3.translate { transform: translateY(-10px); }
4.translate { transform: translate(20px, -10px); }
5
6/* Rotate — rotation around a point */
7.rotate { transform: rotate(45deg); }
8.rotate { transform: rotate(-0.25turn); } /* turns, grad, rad */
9
10/* Scale — resize */
11.scale { transform: scale(1.5); } /* uniform */
12.scale-x { transform: scaleX(2); } /* horizontal stretch */
13.scale-y { transform: scaleY(0.5); } /* vertical squash */
14
15/* Skew — slant */
16.skew { transform: skew(10deg); }
17.skew { transform: skewX(10deg) skewY(5deg); }
18
19/* Matrix — combine all transforms */
20.matrix {
21 transform: matrix(1, 0.5, 0.5, 1, 10, 20);
22} /* scaleX, skewY, skewX, scaleY, translateX, translateY */
23
24/* Chaining — applied right to left */
25.chained {
26 transform: translateX(20px) rotate(45deg) scale(1.2);
27}
28
29/* transform-origin — changes the pivot point */
30.pivot-center { transform-origin: center; }
31.pivot-top-left { transform-origin: 0 0; }
32.pivot-custom { transform-origin: 20px 50%; }

3D Transforms

3D transforms extend the 2D functions with the Z-axis. Requires perspective on the parent to create depth.

transform-3d.css
CSS
1/* Perspective — defines the depth of the 3D scene */
2.stage {
3 perspective: 800px;
4 perspective-origin: center;
5}
6
7/* 3D transforms */
8.rotate-x { transform: rotateX(45deg); }
9.rotate-y { transform: rotateY(45deg); }
10.rotate-z { transform: rotateZ(45deg); }
11.translate-z { transform: translateZ(50px); }
12.scale-z { transform: scaleZ(2) rotateX(45deg); }
13
14/* 3D matrix */
15.matrix3d {
16 transform: matrix3d(
17 1,0,0,0,
18 0,1,0,0,
19 0,0,1,0,
20 0,0,0,1
21 );
22}
23
24/* transform-style — preserves 3D space for children */
25.stage {
26 perspective: 1000px;
27 transform-style: preserve-3d;
28}
29
30/* backface-visibility — hide the reverse side */
31.card-back {
32 backface-visibility: hidden;
33}
34
35/* Card flip example */
36.card-container {
37 perspective: 1000px;
38}
39
40.card {
41 transform-style: preserve-3d;
42 transition: transform 0.6s;
43}
44
45.card:hover {
46 transform: rotateY(180deg);
47}
48
49.card-front, .card-back {
50 backface-visibility: hidden;
51}
52
53.card-back {
54 transform: rotateY(180deg);
55}
preview
Animation Properties Reference

CSS animations have approximately 20 sub-properties across the animation-* and related properties. Understanding each gives you precise control over motion behavior.

PropertyTypeDescription
animationShorthandAll animation-* properties in one declaration
animation-compositionSub-propertyreplace | add | accumulate — how animations combine
animation-delaySub-propertyTime before animation starts (negative for mid-start)
animation-directionSub-propertynormal | reverse | alternate | alternate-reverse
animation-durationSub-propertyLength of one complete cycle
animation-fill-modeSub-propertynone | forwards | backwards | both
animation-iteration-countSub-propertyNumber or infinite
animation-nameSub-propertyName of the @keyframes at-rule
animation-play-stateSub-propertyrunning | paused
animation-timelineSub-propertyauto | scroll() | view() — scroll-driven animations
animation-timing-functionSub-propertyEasing curve for the animation
animation-rangeSub-propertynormal | <length-percentage> — scroll range
animation-range-startSub-propertyStart of animation scroll range
animation-range-endSub-propertyEnd of animation scroll range
animation-shorthand.css
CSS
1/* Complete animation shorthand */
2.element {
3 animation: slideIn 0.6s ease-out 0.2s 1 normal both running;
4}
5
6/* Order: name | duration | timing | delay | count | direction | fill | play-state */
7/* Alternatively, use longhands for clarity */
8.element {
9 animation-name: slideIn;
10 animation-duration: 0.6s;
11 animation-timing-function: ease-out;
12 animation-delay: 0.2s;
13 animation-iteration-count: 1;
14 animation-direction: normal;
15 animation-fill-mode: both;
16 animation-play-state: running;
17 animation-composition: replace;
18}
19
20/* Multiple animations */
21.element {
22 animation:
23 fadeIn 0.5s ease both,
24 slideUp 0.5s ease 0.1s both;
25}
Performance

Smooth 60fps animations require understanding the browser rendering pipeline. The key insight: only transform and opacity are compositor-only properties that skip layout and paint stages entirely.

PropertyTriggers LayoutTriggers PaintTriggers Composite
transform
opacity
width / height
top / left
color / background
filter
animation-performance.css
CSS
1/* GOOD — compositor-only, 60fps */
2.good {
3 transform: translateX(100px);
4 opacity: 0.5;
5}
6
7/* BAD — triggers layout, janky */
8.bad {
9 width: 200px;
10 height: 200px;
11 top: 50px;
12 left: 100px;
13}
14
15/* Use transform instead of top/left for positioning animations */
16/* Instead of */
17.mover { top: 100px; transition: top 0.3s; }
18
19/* Use */
20.mover { transform: translateY(100px); transition: transform 0.3s; }
21
22/* will-change — hint to the browser */
23.will-animate {
24 will-change: transform, opacity;
25 /* Use sparingly — creates a layer, consumes memory */
26}
27
28/* Force GPU acceleration */
29.gpu {
30 transform: translateZ(0);
31 /* Only use if profiling shows benefit */
32}

warning

Overusing will-change creates too many compositor layers and consumes GPU memory. Only apply it to elements you know will animate, and consider removing it after the animation completes via JavaScript.
Scroll Animations

CSS scroll-driven animations allow you to tie animation progress to scroll position using animation-timeline. Combined with the Intersection Observer API for JS-driven triggers, these create engaging scroll-based experiences.

Scroll-Driven Animations (CSS)

scroll-animations.css
CSS
1/* Scroll-timeline — ties animation to scroll progress */
2@keyframes fadeInScroll {
3 from { opacity: 0; transform: translateY(30px); }
4 to { opacity: 1; transform: translateY(0); }
5}
6
7.scroll-reveal {
8 animation: fadeInScroll 1s ease both;
9 animation-timeline: view();
10 animation-range: entry 0% entry 100%;
11}
12
13/* Named scroll-timeline */
14.container {
15 scroll-timeline: --container-scroll block;
16}
17
18.scroll-item {
19 animation: progress 1s linear;
20 animation-timeline: --container-scroll;
21}
22
23@keyframes progress {
24 from { width: 0; }
25 to { width: 100%; }
26}

Intersection Observer (JS + CSS)

intersection-observer.js
JavaScript
1// JavaScript trigger for scroll-based animations
2const observer = new IntersectionObserver((entries) => {
3 entries.forEach(entry => {
4 if (entry.isIntersecting) {
5 entry.target.classList.add('visible');
6 observer.unobserve(entry.target);
7 }
8 });
9}, { threshold: 0.2 });
10
11document.querySelectorAll('.reveal').forEach(el => {
12 observer.observe(el);
13});
reveal-animation.css
CSS
1.reveal {
2 opacity: 0;
3 transform: translateY(30px);
4 transition: opacity 0.6s ease, transform 0.6s ease;
5}
6
7.reveal.visible {
8 opacity: 1;
9 transform: translateY(0);
10}
11
12/* Staggered reveals */
13.reveal:nth-child(2) { transition-delay: 0.1s; }
14.reveal:nth-child(3) { transition-delay: 0.2s; }
15.reveal:nth-child(4) { transition-delay: 0.3s; }
Accessible Animations

Many users experience motion sickness, dizziness, or cognitive overload from animations. The prefers-reduced-motion media query allows you to respect user system preferences for reduced motion.

accessible-animations.css
CSS
1/* Respect user motion preferences */
2@media (prefers-reduced-motion: reduce) {
3 *, *::before, *::after {
4 animation-duration: 0.01ms !important;
5 animation-iteration-count: 1 !important;
6 transition-duration: 0.01ms !important;
7 scroll-behavior: auto !important;
8 }
9}
10
11/* Selective disabling — better than blanket */
12@media (prefers-reduced-motion: reduce) {
13 .bounce, .pulse, .spin {
14 animation: none;
15 }
16
17 .hover-lift {
18 transform: none !important;
19 }
20}
21
22/* Provide reduced-motion alternatives */
23.card {
24 transition: transform 0.3s ease;
25}
26
27.card:hover {
28 transform: scale(1.05);
29}
30
31@media (prefers-reduced-motion: reduce) {
32 .card:hover {
33 transform: none;
34 outline: 2px solid currentColor;
35 }
36}
37
38/* Animate from a state that doesn't require motion */
39@media (prefers-reduced-motion: no-preference) {
40 .fade-in {
41 animation: fadeIn 0.5s ease both;
42 }
43}

best practice

Always wrap non-essential animations in @media (prefers-reduced-motion: no-preference). This ensures that users with vestibular disorders or motion sensitivity can use your site comfortably. For essential motion (loading spinners, progress bars), provide a static alternative.
Best Practices
Only animate transform and opacity for 60fps performance — avoid layout-triggering properties
Use cubic-bezier spring curves (0.34, 1.56, 0.64, 1) for natural-feeling interactions
Keep transition durations short: 150-300ms for micro-interactions, 300-500ms for page transitions
Use ease-out for elements entering the screen, ease-in for elements leaving
Respect prefers-reduced-motion — provide non-animated fallbacks
Staggered animations should use 50-100ms delays for subtle sequencing
Use animation-delay with negative values to start animations mid-cycle
Avoid animating width/height — use transform: scaleX()/scaleY() instead
Use will-change sparingly and only on elements about to animate
Test animations on low-powered devices (e.g., mid-range Android phones)
Use framer-motion or GSAP for complex choreographies that CSS alone cannot handle
Design animations that work at any duration — they should make sense at 0.01ms for reduced motion
🔥

pro tip

Use the browser DevTools Performance panel to record animations and identify jank. Look for red bars in the "Frames" section — these indicate dropped frames. The Animations panel in Chrome DevTools lets you slow down, replay, and inspect individual animations.
Interactive Animation Demo

A visually impressive demo combining multiple animation techniques: transform, opacity, staggered delays, and hover interactions.

preview
$Blueprint — Engineering Documentation·Section ID: CSS-04·Revision: 1.0