ScreenshotNeo

BlogHow-to

How to Create SVG Animations

Learn when to use SVG animation elements, CSS, or JavaScript, with runnable examples, accessibility guidance, and practical debugging tips.

By the ScreenshotNeo team4 October 202610 min read

To create an SVG animation, choose the mechanism that matches what changes: use SVG animation elements for declarative attribute changes, transforms, or motion along a path; use CSS keyframes or transitions for style changes; and use JavaScript when motion depends on interaction, data, or application state. Keep the SVG inline in HTML when you need page CSS or script to control it. Provide a reduced-motion alternative or a way to pause motion.

1. Choose an animation method

Method Best suited to Where the animation is defined
SVG animation elements Attribute values, transforms, and movement along a path Inside the SVG markup
CSS animations and transitions Style changes such as opacity, fill, or transforms Stylesheets or a style block
JavaScript and the SVG DOM Interaction, application state, or dynamically calculated values Page script

Consider the intended embedding too. Inline SVG can be styled and scripted by the containing page. An SVG referenced as an image has a different relationship to the page’s CSS and scripts, so verify the exact animation feature in the context where you will deliver it.

2. Animate an SVG attribute with <animate>

The <animate> element changes an attribute or property over time. Place it inside the shape that it controls. This complete SVG moves a circle from the left edge toward the right edge of its viewBox and repeats:

<svg viewBox="0 0 300 100" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="moving-title">
  <title id="moving-title">A blue circle moving from left to right</title>
  <circle cx="0" cy="50" r="15" fill="blue">
    <animate attributeName="cx" from="0" to="300" dur="3s" repeatCount="indefinite" />
  </circle>
</svg>

The important settings here are:

  • attributeName names the value to animate, here the circle’s horizontal center, cx.
  • from and to define the starting and ending values.
  • dur sets the duration. Use a time such as 3s.
  • repeatCount can be a number or indefinite for continuous repetition.

For a discrete change rather than an interpolation, use <set>. For example, a set can change an attribute after a delay. Consult the target browser’s support for the precise timing and attribute behavior you need.

3. Animate transforms and motion paths

A transform value combines multiple components, so use <animateTransform> when you want an SVG element to rotate, scale, or translate. For example, this rotates a rectangle around the SVG origin:

<svg viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="rotating-title">
  <title id="rotating-title">A rectangle rotating around the SVG origin</title>
  <rect x="45" y="20" width="30" height="30" fill="tomato">
    <animateTransform attributeName="transform" type="rotate"
      from="0 60 60" to="360 60 60" dur="4s" repeatCount="indefinite" />
  </rect>
</svg>

The three numbers in the rotation values represent the angle and the rotation center coordinates. Adjust the center to suit your drawing. The rectangle above rotates around the center of the viewBox.

Use <animateMotion> to move an object along a path. The path describes the route; the animated element is the object that follows it:

<svg viewBox="0 0 240 120" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="path-title">
  <title id="path-title">A circle following a curved path</title>
  <path d="M 20 90 C 70 10, 170 10, 220 90" fill="none" stroke="#bbb" />
  <circle r="8" fill="royalblue">
    <animateMotion dur="3s" repeatCount="indefinite"
      path="M 20 90 C 70 10, 170 10, 220 90" />
  </circle>
</svg>

SVG animation elements are useful when the timeline belongs with the artwork and can be described declaratively. Check support for the exact feature and the way the SVG is embedded; feature behavior is not guaranteed to be identical in every browser or image context. MDN describes <animate> as widely available across browsers since January 2020, but that summary does not guarantee identical support for every animation feature or embedding mode. See the MDN reference for <animate> and the W3C SVG 2 introduction.

4. Animate SVG with CSS

CSS keyframes are a practical choice when the desired effect is expressed through CSS properties. This inline SVG pulses by scaling and changing opacity:

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS animation in SVG</title>
<style>
  .pulse {
    transform-box: fill-box;
    transform-origin: center;
    animation: pulse 1.2s ease-in-out infinite alternate;
  }
  @keyframes pulse {
    to { transform: scale(1.25); opacity: 0.65; }
  }
  @media (prefers-reduced-motion: reduce) {
    .pulse { animation: none; }
  }
</style>
<svg viewBox="0 0 100 100" role="img" aria-labelledby="pulse-title"
     xmlns="http://www.w3.org/2000/svg">
  <title id="pulse-title">A pulsing circle</title>
  <circle class="pulse" cx="50" cy="50" r="20" fill="royalblue" />
</svg>
</html>

@keyframes defines the animated property values; animation sets the duration, timing, repetition, and direction. A CSS transition is different: it smoothly interpolates a property when some other change occurs, such as adding a class or hovering over an element. Use a transition for a state change and keyframes for a timeline that runs on its own.

/* The transition runs when JavaScript or another state change adds .active. */
.icon { transition: transform 180ms ease, fill 180ms ease; }
.icon.active { transform: rotate(15deg); fill: tomato; }

CSS support depends on the property and SVG context. Test the property you intend to animate in the browsers and embedding modes your page supports; do not assume every SVG property behaves like an ordinary HTML box.

5. Use JavaScript when animation depends on state

JavaScript can access SVG elements and their attributes through the DOM. It is appropriate when the animation responds to an event or application data. This runnable example moves a circle in response to a button and respects the reduced-motion preference by leaving the circle stationary for users who request less motion:

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Move an SVG circle with JavaScript</title>
<button id="move" type="button">Move circle</button>
<svg viewBox="0 0 320 80" width="320" height="80"
     xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="js-title">
  <title id="js-title">A circle moved by a button</title>
  <circle id="dot" cx="20" cy="40" r="12" fill="seagreen" />
</svg>
<script>
  const dot = document.querySelector('#dot');
  const button = document.querySelector('#move');
  const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');

  button.addEventListener('click', () => {
    const currentX = Number(dot.getAttribute('cx'));
    const nextX = currentX >= 300 ? 20 : currentX + 40;

    if (reducedMotion.matches) {
      dot.setAttribute('cx', String(nextX));
      return;
    }

    dot.animate(
      [{ cx: currentX }, { cx: nextX }],
      { duration: 300, easing: 'ease-out', fill: 'forwards' }
    );
    dot.setAttribute('cx', String(nextX));
  });
</script>
</html>

The SVG DOM itself lets scripts read and update SVG elements, attributes, and properties, and graphical elements can respond to events. This example uses the Web Animations API to interpolate a DOM attribute; verify support for that API and the animated attribute in your target browsers. For a simpler state change, update the attribute directly or toggle a class and let CSS handle the transition. The W3C describes declarative SVG animation and script-driven animation in its SVG 2 introduction.

6. Make motion accessible

Motion can cause discomfort or health effects for some people, especially blinking or flashing effects. Follow these practices:

  • Honor prefers-reduced-motion: reduce for CSS-driven effects, and offer a static or simpler state.
  • For SVG-markup or script-driven animation, add a pause or disable control when the motion is persistent or essential content moves.
  • Avoid rapid flashing. Do not rely on a CSS media query to control animation embedded in a separate SVG image or driven by another mechanism.
  • Give meaningful graphics an accessible name, such as with <title> and aria-labelledby; do not make animation the only way to communicate important information.

MDN discusses motion sensitivity and alternatives in its reduced-motion media query guide.

7. Test and debug the animation

  1. Open the SVG directly and inside the actual page. An animation that works inline may behave differently when the SVG is used through an image element.
  2. Check the SVG console and markup for misspelled attributes, malformed XML, invalid values, and missing namespaces.
  3. Confirm the animated attribute exists on the element. For example, cx applies to a circle, while transform requires transform syntax.
  4. Temporarily use a visible stroke or fill, a longer duration, and a finite repeat count to make the movement easier to inspect.
  5. For CSS, inspect computed styles and confirm that the selector matches the SVG element. Verify that the animated property is supported in the chosen context.
  6. For JavaScript, confirm the script runs after the SVG exists and that the selected element is not null.
Symptom Likely cause Fix
Nothing moves Wrong attribute name, invalid values, or animation markup placed outside the intended SVG element Check the element and attribute, inspect the console, and try the minimal inline example above.
CSS animation works in one context only The SVG is embedded differently or the selected property has context-specific support Test inline and image-based use separately; check compatibility for that property and delivery mode.
Rotation happens around an unexpected point The transform origin or rotation center is not where the drawing’s visual center is Set the intended center in animateTransform values, or set transform-box and transform-origin for CSS.
Circle disappears at the edge The animated center reaches the viewBox boundary while the circle has a nonzero radius Keep the center at least one radius inside the edge, or expand the viewBox.
JavaScript cannot find the shape The query runs before the SVG is parsed, or the selector does not match Place the script after the SVG or wait for DOM readiness; check the ID and spelling.
Reduced-motion setting has no effect The animation is declarative SVG markup, scripted, or in a separately loaded image Add a mechanism appropriate to that animation, such as a pause control or a static alternate asset.

8. Performance, reliability, and delivery

Keep each animation limited to the elements and properties that need to move. Prefer a simple declarative or CSS solution when it fully describes the effect; use scripting when behavior genuinely depends on state. The source material does not establish a universal performance winner between these methods, and actual results depend on the artwork, properties, browser, and page. Profile the real page if animation load matters.

For reliable delivery, validate the SVG markup, include a sensible static appearance before animation starts, and test the target browsers and embedding mode. Avoid making a critical label or instruction depend on a moving element. Reduced-motion behavior should be checked separately from the default animation.

9. Capture an SVG animation for review

A screenshot is a still frame, so decide which point in the animation you want to document. A self-running animation may not be at the same point on every capture. For repeatable review, use a static state or add a page control that places the graphic in a known state before capturing.

You can render the page in a browser and capture it, or use a screenshot API. ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It accepts a URL and returns a screenshot or PDF; its site describes the service, and the API documentation lists request options.

Or skip the browser setup

Once your SVG is on a page, this cURL request captures it as a WebP image:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Replace the example URL with your page URL. Keep the API key private in server-side code. Python:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Read the ScreenshotNeo API docs for request parameters and response details. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for the free plan.

Frequently asked questions

Can an SVG animate when used as an image?

It depends on the animation feature and how the image is loaded. Test the exact browser and embedding mode; use inline SVG when the page needs to control it with CSS or JavaScript.

Should I use SVG animation elements or CSS?

Use SVG elements for declarative SVG attribute, transform, or path changes. Use CSS when the effect is naturally a style animation or transition. Choose based on the change and delivery context.

Do I need a JavaScript library?

No. The SVG DOM can be accessed directly from JavaScript. A library is a project choice, not a requirement for basic SVG animation.

How do I stop animation for users who prefer less motion?

Use the reduced-motion preference for CSS animations, and provide an appropriate static state or pause control for declarative and scripted animation.