Advanced Topics: Animation with CSS and SMIL

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-angle to 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., 0s for immediate, 1s for 1-second delay, click for on click).
  • repeatCount: How many times the animation should repeat (indefinite for infinite loop, a number for specific count).
  • fill: What happens after the animation ends (freeze to hold end state, remove to 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 cx attribute from 50 to 250 over 3 seconds and repeats indefinitely.
  • It also animates its fill attribute through a sequence of colors, controlled by values and keyTimes.
  • The rectangle uses <animateTransform> to rotate itself 360 degrees around its center (40 120 relative to the original x=20, y=100 makes the center 20+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

  1. Bouncing Ball with CSS:

    • Draw a circle.
    • Use CSS @keyframes to make the circle appear to bounce vertically, starting from translateY(0), going down to translateY(50px), and back up. Make the timing function ease-in for the fall and ease-out for the rise to simulate gravity.
    • Add a subtle scaleX change at the bottom of the bounce to make it look like it’s squashing slightly.
  2. 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 @keyframes and transform: rotate() to make it continuously spin.
    • Experiment with opacity or stroke-dashoffset for a more sophisticated look (e.g., a “drawing” effect as it spins).
  3. 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 changing x, y coordinates of specific points if it’s a <path>, or potentially using a more complex animateTransform with skew and scale). This is more challenging and might be easier with a <path> that has carefully chosen points.
  4. 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, and box-shadow (using filter: drop-shadow() for SVG). Make the transitions visually appealing.
  5. Traffic Light Sequence (Advanced CSS/JS Concept):

    • Take your traffic light from earlier chapters.
    • Using CSS keyframes or 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-delay and potentially target specific lights with different keyframes.