9. Advanced Topics: Animation with CSS and SMIL
Animation is where SVG truly shines, allowing you to transform static graphics into dynamic and engaging experiences. This chapter explores two primary methods for animating SVGs: using CSS (transitions and keyframes) and using native SVG animation elements (SMIL). While JavaScript libraries like GSAP offer the most sophisticated control (and are briefly mentioned), we’ll focus on browser-native solutions first.
9.1 Animation with CSS
CSS provides a powerful and performant way to animate SVG elements. It leverages the browser’s rendering engine for smooth animations, often taking advantage of hardware acceleration.
9.1.1 CSS Transitions
Transitions are ideal for animating changes between states, typically on hover or focus.
Example: Hover Grow and Color Change
<svg width="200" height="150" viewBox="0 0 200 150">
<style>
.my-circle {
fill: #3498db;
stroke: #2980b9;
stroke-width: 3;
transform-origin: center;
transition:
fill 0.3s ease-out,
transform 0.3s ease-out,
stroke-width 0.3s ease-out;
}
.my-circle:hover {
fill: #e74c3c;
transform: scale(1.2) rotate(30deg);
stroke-width: 6;
}
</style>
<circle cx="100" cy="75" r="50" class="my-circle" />
</svg>
Explanation: On hover, the circle smoothly changes color, grows, rotates, and its stroke becomes thicker, thanks to the transition property. transform-origin: center is crucial for scaling and rotation to happen around the circle’s center.
9.1.2 CSS Keyframe Animations
Keyframe animations provide more control over multi-step, continuous, or repeating animations.
Example: Pulsing and Rotating Icon
<svg width="200" height="200" viewBox="0 0 200 200">
<style>
@keyframes pulse-and-rotate {
0% {
transform: scale(1) rotate(0deg);
opacity: 0.8;
fill: #f1c40f;
}
50% {
transform: scale(1.1) rotate(180deg);
opacity: 1;
fill: #e67e22;
}
100% {
transform: scale(1) rotate(360deg);
opacity: 0.8;
fill: #f1c40f;
}
}
.animated-star {
animation: pulse-and-rotate 3s ease-in-out infinite alternate;
transform-origin: center; /* Crucial for correct rotation/scaling */
/* Default styles */
fill: #f1c40f;
stroke: #e67e22;
stroke-width: 2;
}
</style>
<polygon
points="100,20 120,80 180,80 130,120 150,180 100,150 50,180 70,120 20,80 80,80"
class="animated-star"
/>
</svg>
Explanation: The star continuously scales, rotates, changes opacity, and shifts color through the defined keyframes. infinite alternate makes it repeat forever and reverse direction each cycle.
New in CSS (2025 trends): @property and linear()
@property: This CSS rule allows you to define custom properties (--my-var) with type, initial value, and inheritability. Crucially, it makes these custom properties animatable. For example, you could animate--gradient-angleto smoothly rotate a gradient.linear()easing function: Provides a way to define more precise and complex easing curves for animations, approximating spring-like effects without JavaScript.
While full examples of these are more advanced, be aware that modern CSS is increasingly powerful for SVG animation.
9.2 Animation with SMIL (Synchronized Multimedia Integration Language)
SMIL is an XML-based language for defining animations directly within SVG markup. It’s an older standard, and while it’s well-supported in most modern browsers (especially Firefox), Chrome and Safari have largely deprecated or moved away from its direct support in favor of CSS and Web Animations API. However, it’s still good to understand its concepts as it’s part of the SVG specification and can sometimes be found in existing SVGs.
SMIL animations are declarative, meaning you describe what you want to happen, rather than how to do it step-by-step (like JavaScript).
Common SMIL Elements:
<animate>: Animates a single attribute (e.g.,x,y,fill,transform).<animateTransform>: Specifically animates a transformation (translate,rotate,scale,skew).<animateMotion>: Animates an element along a defined path.<set>: Sets an attribute to a specific value at a given time (no interpolation/transition).
Key Attributes for SMIL Animation:
attributeName: The name of the SVG attribute to animate (e.g.,cx,fill,transform).from,to: Starting and ending values for the animation.dur: Duration of the animation (e.g.,2s,500ms).begin: When the animation starts (e.g.,0sfor immediate,1sfor 1-second delay,clickfor on click).repeatCount: How many times the animation should repeat (indefinitefor infinite loop, a number for specific count).fill: What happens after the animation ends (freezeto hold end state,removeto return to start state).keyTimes: Semicolon-separated list of time values (0 to 1) that control the pace of the animation.values: Semicolon-separated list of values for multi-step animations (like CSS keyframes).calcMode: Specifies how the animation values are interpolated (e.g.,linear,discrete,paced,spline).path(for<animateMotion>): Defines the path data for motion.href(for<animateMotion>): References an existing<path>by ID for motion.
Example: SMIL Circle Movement and Color Change
<svg width="300" height="200" viewBox="0 0 300 200">
<circle cx="50" cy="50" r="20" fill="purple">
<animate
attributeName="cx"
from="50"
to="250"
dur="3s"
repeatCount="indefinite"
fill="freeze"
begin="0s"
/>
<animate
attributeName="fill"
values="purple; blue; red; green; purple"
keyTimes="0; 0.25; 0.5; 0.75; 1"
dur="5s"
repeatCount="indefinite"
begin="0s"
/>
</circle>
<rect x="20" y="100" width="40" height="40" fill="orange">
<animateTransform
attributeName="transform"
type="rotate"
from="0 40 120"
to="360 40 120"
dur="4s"
repeatCount="indefinite"
/>
</rect>
</svg>
Explanation:
- The circle animates its
cxattribute from 50 to 250 over 3 seconds and repeats indefinitely. - It also animates its
fillattribute through a sequence of colors, controlled byvaluesandkeyTimes. - The rectangle uses
<animateTransform>to rotate itself 360 degrees around its center (40 120relative to the originalx=20, y=100makes the center20+20, 100+20).
SMIL Compatibility Note: While SMIL is part of the SVG spec, browser support is inconsistent. CSS animations are generally preferred for performance and broader compatibility. The Web Animations API (WAAPI), a JavaScript API, provides programmatic control with native browser performance, bridging the gap between CSS and SMIL. For complex, synchronized animations across many elements, JavaScript libraries like GreenSock Animation Platform (GSAP) are often the industry standard, offering robust cross-browser support and advanced features like path morphing and timeline control.
Exercises/Mini-Challenges
Bouncing Ball with CSS:
- Draw a circle.
- Use CSS
@keyframesto make the circle appear to bounce vertically, starting fromtranslateY(0), going down totranslateY(50px), and back up. Make the timing functionease-infor the fall andease-outfor the rise to simulate gravity. - Add a subtle
scaleXchange at the bottom of the bounce to make it look like it’s squashing slightly.
Loading Spinner (CSS):
- Create a simple loading spinner using one or two SVG elements (e.g., a line, a circle segment, or a path).
- Use CSS
@keyframesandtransform: rotate()to make it continuously spin. - Experiment with
opacityorstroke-dashoffsetfor a more sophisticated look (e.g., a “drawing” effect as it spins).
Waving Flag (SMIL - optional, for learning):
- Draw a simple rectangular flag using
<rect>or<path>. - Try to animate its shape using SMIL
<animate>elements to create a subtle waving effect (e.g., by changingx,ycoordinates of specific points if it’s a<path>, or potentially using a more complexanimateTransformwithskewandscale). This is more challenging and might be easier with a<path>that has carefully chosen points.
- Draw a simple rectangular flag using
Button Hover with Multiple CSS Properties:
- Create an SVG button (a rectangle with text).
- On hover, transition multiple CSS properties simultaneously:
background-color(fill),border-radius(rx/ry),transform: translateY, andbox-shadow(usingfilter: drop-shadow()for SVG). Make the transitions visually appealing.
Traffic Light Sequence (Advanced CSS/JS Concept):
- Take your traffic light from earlier chapters.
- Using CSS
keyframesor JavaScript (if you want to peek ahead), animate the lights in a sequence (red -> green -> yellow -> red). - For CSS, you might need to use
animation-delayand potentially target specific lights with different keyframes.